その3では、OpenframeworksのiPhone実機テストと、Wifi連携の概要までを説明しました。takesan.hatenablog.com今回はiPhoneとEdison双方のプログラムソースを紹介します。
プログラムが動作するまで、ライブラリのインストールなども必要なので、必要部分に記載します。また、OMURON D6Tが動く環境であれば、スイッチサイエンス版Eagletでなくとも同じソフトで動作可能です。まず、復習の意味でどんなことをするのか、動画確認から。
この動画ではEdisonに接続されたμOled3028でiPhoneの設定を変更していますが、この表示機器についての制御方法は、今回含まれません(次回以降)。赤外線非接触センサーの解像度が、今の4X4から16X16くらいになったら、まさにサーモグラフィーですね!!。(OMRONでは16X16のSPIセンサーが企業向けに販売されてるようですが、ボクに売ってくれないかな)www.omron.co.jp
4X4(センサー本来の能力)で温度表示。最高最低温度が表示されている。Edisonとの通信状態はランプイラストの点滅。
スライダーで61X61に補間。ドットの大きさを変えられるので、カメラ画像を確認できる。同じセンサーとは思えないのでは?(写真はセンサーとカメラ位置がちょっとずれ気味。カメラとセンサーの画角がたまたまほとんど同じなので、合わせるのはとても簡単ですが)
動作内容
ポート番号を設定して、bonjourで相手のipアドレスを手に入れ、そのアドレスを使ってOSCプロトコルを使ってEdisonからOMURON D6TのデータをWifi送信します。
iPhoneのopenframeworks環境ととEdisonのPython環境には、それぞれbonjourとOSC通信ライブラリが必要になります。今回iPhone側はiOSのGUIを使っていますので、そのあたりも簡単に説明します。今回のソースを利用すれば、Edisonに接続したセンサー値を利用してiPhoneでカッコよく処理するなんてことが簡単に実現できますぞ!!。
OSC通信は、同一LAN内でしか送受信できませんが、iPhoneのデザリングでなんとかなりそうな気がします。そうすればBLEなんかわざわざ勉強しなくてもいいかも。(今後の楽しみに取っときますーー>10/27下記の記事を書きました)takesan.hatenablog.com
iOSのOpenframeworksによるプログラムソース構築
まず、自分のMacにOpenframeworksをインストールしてください。ダウンロードして解凍したフォルダの中の addonsフォルダの中に以下のaddonを追加します
robotconscience/ofxBonjour · GitHub前にも書きましたがダウンロードして解凍したフォルダ名をofxBonjourに変更します。このaddonは古いので最新の方が良いかもしれませんが、動いたのでここでは最新版を使いません。ofxOSCは、標準addonなのでインストールの必要はありません。
さらにダウンロードして解凍したOpenframeworksフォルダの中「projectGenerator_ios/projectGenerator.app 」をダブルクリック。プロジェクト名を付け、addonにofxOSCとofxBonjourを選択したら、GENERTE PROJECTボタンを押します。
今作ったプロジェクトは、/apps/myApps に入っていますので、その中のプロジェクトファイルをダブルクリックします。Xcodeが立ち上がったら、前回説明したように、iOS Deployment Targetを最新版にします。これで一応プログラムを入力する準備ができました。
ビルド時の注意なのですが、今回紹介する ofxOSC で ‘ip/UdpSocket.h’ file not found が出る時は、Build SettingsのUser Header Serch Pathsに次のパスを入れると「 ../../../addons/ofxOsc/libs/oscpack/src 」正常にビルドできるようになります。
Xcodeに慣れていないと、予想外のところを触ってしまって、エラーが続出してしまうことがあります。そんな時は迷わずOpenframeworks自体を新しいものに変えてしまいます。(時間の無駄なので、初心者に超オススメ。)
それでは、ソースです。GUIフォルダの作り方は、ofApp.mmのコメント中に入れておきました。このフォルダを作った後、内容を変更してください。今回は自分のためにもコレデモか!!と言えるくらいコメントを入れておきましたので、内容を確認してみてください。対象のiPhone は6plus です。
ファイル構成は下図参照
ofApp.h
#pragma once #include "ofMain.h" #include "ofxiOS.h" #include "ofxiOSExtras.h" #include "ofxBonjourIp.h" #include "ofxOsc.h" // listen on port 7777 #define PORT 7777 #define NUM_MSG_STRINGS 20 class ofApp : public ofxiOSApp { public: void setup(); void update(); void draw(); void exit(); void touchDown(ofTouchEventArgs & touch); void touchMoved(ofTouchEventArgs & touch); void touchUp(ofTouchEventArgs & touch); void touchDoubleTap(ofTouchEventArgs & touch); void touchCancelled(ofTouchEventArgs & touch); void lostFocus(); void gotFocus(); void gotMemoryWarning(); void deviceOrientationChanged(int newOrientation); // OSC イベント追加 void onPublishedService(const void* sender, string &serviceIp); void onDiscoveredService(const void* sender, string &serviceIp); void onRemovedService(const void* sender, string &serviceIp); // remember to add the CFNetwork framework for ios ofxBonjourIp* bonjour; // iOSGUI int botton_new,botton_old,sli,div1,temp_sw; ofxOscReceiver receiver; int current_msg_string; string msg_strings[NUM_MSG_STRINGS]; float timers[NUM_MSG_STRINGS],scale_cam; float tdata[16],ttdata[3800]; //font ofTrueTypeFont verdana14,verdana30,cooperBlack60; //OSC data int cam_no,camdata; string ondoState; //iPHONE CAMERA ofVideoGrabber cam; ofImage lamp_on,lamp_off; };
main.mm
#include "ofMain.h" #include "ofApp.h" //以下 WEB上では色々な設定があるが、その中で一番安定しているiPhone6+のRetina詳細画面の設定 int main(){ ofAppiOSWindow * window = new ofAppiOSWindow(); window->enableAntiAliasing(2); window->enableRetina(); window->enableRendererES2(); ofSetupOpenGL(1704,960, OF_FULLSCREEN); //<--この値を変えても1704,960のまま!!はっきり言えば数値はなんでも良い ofRunApp(new ofApp); }
ofApp.mm
#include "ofApp.h" #include "MyGuiView.h" MyGuiView *gui; //kyokusenn int a1,b1,c1,d1,aaa; float a,b,c,d; //-------------------------------------------------------------- float sp(int x){ //ラグランジュ変換用関数 return (x-aaa)*(x-aaa*2)*(x-aaa*3)*a+x*(x-aaa*2)*(x-aaa*3)*b+x*(x-aaa)*(x-aaa*3)*c+x*(x-aaa)*(x-aaa*2)*d; } void ofApp::setup(){ // iOS GUI 設定 // 田所先生のWEB上のやり方だとXcode自体が少し昔のものなのでうまくいかなかった。他の方も // http://www.creativeapplications.net/tutorials/integrating-native-uikit-to-your-existing-openframeworks-ios-project/ // でさらに詳しく説明されているが、これでも上手くいかない。また、OFに添付されたいるiOSのサンプル(iPhoneGuiExample)は動くが設定の経緯が分からない。 // 結局 GUI フォルダを 作って 3つのファイルを自動で作成させ 自動で作成される xxxx.m の拡張子を .mm に変えるまでは田所先生の説明、 // すなわちnewfile->iOS->Source->Cocoa touch Class->Next->Class名変更、サブクラスはそのまま、Also creat XLB fileにチェック // 次に各ファイルの内容とボタン作成の操作を上記ブログを参考にして変更するとうまくいった。慣れればすごく簡単。以下2行ofApp.mm内での設定 gui = [[MyGuiView alloc] initWithNibName:@"MyGuiView" bundle:nil]; [ofxiOSGetGLParentView() addSubview:gui.view]; ofSetFrameRate(20); //EDISON側のデータ送信が遅すぎ、60にするとデータが途切れてしまうので20程度まで下げる。 ofBackground(0); //EDISONからデータが来ているときの表示画像取り込み データはこのプロジェクトの bin/data 以下に入れておく //iPhonではどこに入ってるかなんて考える必要なし。このフォルダに入れればiphoneで再現できる(どこかに入っている)。 lamp_on.allocate(78, 140, OF_IMAGE_COLOR); lamp_on.loadImage("img01.png"); lamp_off.allocate(78, 140, OF_IMAGE_COLOR); lamp_off.loadImage("img04.png"); // iPHONE カメラ初期設定(Grabber)は切替が必要なためここでは実行しない // フォント読み込み->フォントファイルは プロジェクトのbin/dataホルダに入れておく。ここでサイズを変えてもOK (実行時エラーレポートが出るが) // setup()内では、OF 上で表示するフォントを あらかじめ定義 // たまに読み込み時にFONT関連の実行時エラーとなるが iOS Deployment Taget を一旦 6.0とかに落とすと なぜか実行できる。 // iOS シュミレーターの問題のような気がする。 ofTrueTypeFont::setGlobalDpi(72); verdana30.loadFont("verdana.ttf", 20, true, true); verdana30.setLineHeight(34.0f); verdana30.setLetterSpacing(1.035); cooperBlack60.loadFont("cooperBlack.ttf", 60, true, true); cooperBlack60.setLineHeight(64.0f); cooperBlack60.setLetterSpacing(1.037); //bonjour,OSC とも今回はサーバー設定なのでIPは必要無い。EDISON側では必要なので、bonjourでサーバーのIPを探してからOSC送信する // bonjour スタート bonjour = new ofxBonjourIp(); bonjour->addEventListeners(this); // optional // find me (server) bonjour->startService(); // 引数に何も指定しなければ bonjour アドオンの ofxBonjourIp.h の設定のまま。(次のコメント内容) //bonjour->startService("_ofxBonjourIp._tcp.", "", 7777, "local"); // find another device (client)- note will not discover itself bonjour->discoverService(); // discover other device with defaults. //bonjour->discoverService(type, domain); // ここからOSC設定。設定はサーバーなのでポート番号のみ。 ポート番号はofAPP.hで定義。番号設定はある程度自由。 cout << "listening for osc messages on port " << PORT << "\n"; receiver.setup( PORT ); current_msg_string = 0; ondoState = ""; botton_new = 0; //イベント時の ボタンの値 iOSGUI と 4Dsysからの受信値で共用 botton_old=0; //現在の ボタンの値 iOSGUI と 4Dsysからの受信値で共用 sli=100; //スライダーGUI初期値 div1=1; //スライダーGUI初期値 temp_sw=0; //温度数値表示GUI初期値 } //-------------------------------------------------------------- void ofApp::update(){ //updateとdrawは同じような処理をする印象を受けるが、update 内に図形作成命令を書いても画面に表示しない。図形表示はdraw()に記述すること。 if(botton_old!=0) { cam.update(); } camdata=1; // 以下OSCデータ受信処理 while( receiver.hasWaitingMessages() ){ // get the next message ofxOscMessage m; receiver.getNextMessage( &m ); // 温度データをSTRINGで受け取る /以下のコマンド及びデータは、送受信双方で同じ記述をするだけでOSC送受信ができてしまう!!簡単 if( m.getAddress() == "/ondo" ){ ondoState = m.getArgAsString( 0 ) ; camdata=0; } // 4DsysからのボタンデータをINTで受け取る-->カメラの切り替えだけ else if( m.getAddress() == "/cam" ){ cam_no = m.getArgAsInt32( 0 ) ; // printf(" CAMno=%i",cam_no); botton_new=cam_no; } } } //-------------------------------------------------------------- void ofApp::draw(){ ofSetColor(255); if(botton_old!=0){ float scale_cam=680/cam.getWidth(); //カメラデータの拡大率を計算 cam.draw((ofGetWidth()-680)/2, 200,int(cam.getWidth()*scale_cam),int(cam.getHeight()*scale_cam)); } if(botton_new != botton_old){ switch (botton_new) { case 0: cam.close(); //カメラを表示しない場合 botton_old=botton_new; break; case 1: if(botton_old != 0) cam.close(); cam.setDeviceID(0); // 0又は省略で通常カメラ 必ずinitGrabberの前に設定する cam.initGrabber(640,480, OF_IMAGE_COLOR);//カメラ表示の大きさは何種類かあるが左が一番無難。数字を適当に //変えてもシステム設定通りでないと変更されない。 scale_cam=680/cam.getWidth(); cam.draw((ofGetWidth()-680)/2, 200,int(cam.getWidth()*scale_cam),int(cam.getHeight()*scale_cam)); botton_old=botton_new; break; case 2: if(botton_old != 0) cam.close(); cam.setDeviceID(1); // 1はfacetime カメラ cam.initGrabber(640,480, OF_IMAGE_COLOR); scale_cam=680/cam.getWidth(); cam.draw((ofGetWidth()-680)/2, 200,int(cam.getWidth()*scale_cam),int(cam.getHeight()*scale_cam)); botton_old=botton_new; break; default: break; } } //Edison側の命令をボタンに反映させたいが、設定方法がわからないのでダメ押しの表示。 if(botton_old==0){ ofSetColor(139, 137, 137); cooperBlack60.drawString("NoCamera", 300, 1250); } else if(botton_old==1){ ofSetColor(124, 205, 124); cooperBlack60.drawString("FrontCamera", 250, 1250); } else{ ofSetColor(205, 85, 85); cooperBlack60.drawString("FaceCamera", 250, 1250); } //****************ここから 温度データを 4X4->最大61X61 に変換して 画面に表示******************** // 頭が現役じゃないので原始的です。 // ここをなんとかすると表示が速くなるが、EDISON側のPYTHON処理データ送信が遅いのであまり影響ない if(ondoState.length()>= 48){ ofDisableAlphaBlending(); //データが送られて来た場合のサイン表示 ofSetColor(105,105,105); ofRect(142, 20, 676, 140); ofSetColor(255,210,0); cooperBlack60.drawString(" Edison---->", 100, 100); lamp_on.draw(650,20); //4X4の文字データを浮動小数点に変換 245ー>24.5 int kk=0; //カメラ連動なしでセンサー内容表示の場合 if(botton_old==0 ){ for (int k=0; k<16; k++){ tdata[k]=ofToFloat(ondoState.substr((3+int(k/4)*4-k%4)*3,3))*0.1; kk++; } } //反転の場合-->センサーとカメラを連動(前も後ろも同じ) else { int kk=0; for (int k=0; k<48; k=k+3){ tdata[kk]=ofToFloat(ondoState.substr(k,3))*0.1; kk++; } } // たかだか 4X4 のセンサーなのに 補間で 画像が立体的に見えてくる。以下補間処理部分 // 送信スピードが(python側)が遅いので、スピードを考慮していない。2次元ではなく1次元配列とした // 補間方法は4点のラグランジュ 計算は複雑だが 等分に比べピークが出ない。あくまでも推測値なので現実とは多少違う。 // 描画終了までに1画面最大 3721+244=3964点について膨大な単純計算をしているが、スピードはあまり気にならない。ネイティブすごい!! aaa=div1; //最大20等分 X方向 等分補間 iOS GUI のスライダーとリンク(div1) 4X4-->61X61 可変 //aaa=10; //テスト用 //以下X方向についてtdata を 補間用配列ttdataに温度を補間して配置 //ラグランジュ用定数 X方向距離は1単位 正方形なので、Y方向も共用 a1=-aaa*-aaa*2*-aaa*3; b1=aaa*(aaa-aaa*2)*(aaa-aaa*3); c1=aaa*2*(aaa*2-aaa)*(aaa*2-aaa*3); d1=aaa*3*(aaa*3-aaa)*(aaa*3-aaa*2); for(int y=0;y<4;y++){ //ラグランジュ用定数 X方向4点の温度 a=tdata[0+y*4]/a1; b=tdata[1+y*4]/b1; c=tdata[2+y*4]/c1; d=tdata[3+y*4]/d1; int xxx=y*aaa*(3*aaa+1); for (int xx=0 ;xx < aaa*3+1 ; xx++){ ttdata[xx+xxx]=sp(xx); } } //以下Y方向の処理。上記で引き伸ばしたX方向4点について、全点の温度補間処理実行 int yy1=aaa*3+1; for(int xx=0;xx<yy1;xx++){ //スプライン用定数 Y方向4点の温度 a=ttdata[xx]/a1; b=ttdata[xx+yy1*aaa]/b1; c=ttdata[xx+yy1*aaa*2]/c1; d=ttdata[xx+yy1*aaa*3]/d1; for(int yy=0;yy<yy1;yy++){ //基準4点も再計算してるので効率悪いが(最大244箇所)めんどくさいのでこのまま ttdata[xx+yy1*yy]=sp(yy); } } //色分け用 最大最小値抽出->元のデータ16個について float omin=100; float omax=tdata[0]; int min_no=0,max_no=0; for (int k=0; k<16; k++){ if(tdata[k] >= omax) {omax=tdata[k]; max_no=k;} if(tdata[k] <= omin) {omin=tdata[k]; min_no=k;} } //最大最小値の位置を最大3721個に補間したデータ位置に変換 //ラグランジュ補間なので測定値より最大最小が大きくなる場合があり色変換時、山が削られるが、この次挑戦 int min_R=(min_no%4)*aaa+int(min_no/4)*yy1*aaa; int max_R=(max_no%4)*aaa+int(max_no/4)*yy1*aaa; //************************描画開始************************** // if (botton_old!=0) ofEnableBlendMode(OF_BLENDMODE_MULTIPLY); //画像とブレンド 透明にするため float pic=676.0/yy1; //1ヶ所毎の分割表示の大きさ int型だと大きさが変わるのでfloat for (int tt=0;tt<yy1*yy1;tt++){ //色の差をはっきり出すために画面ごとに最小最大値の濃淡を変える。結果的に動いているものを目で追いやすくなった。 int min_max=ofMap(ttdata[tt],omin, omax, 0, 255); //画面再描画ごとに 濃淡の上下を変える RGB 0〜255 ofSetColor(min_max,0,255-min_max,100); //単純な赤青の濃淡が一番綺麗かも。 ofRect((tt%yy1)*pic+142,(tt/yy1)*pic+307,pic*sli/100,pic*sli/100); // ピクセルの大きさは iOS GUI のスライダーとリンク(sli) } // せっかく温度を測定できるセンサーなので,数値を表示ー>センサーの一応正確な読み取り場所である 4X4 の場所に限定 ofSetColor(255); if(temp_sw==0){ //iOS GUI のスイッチで、最大最小値だけを表示 verdana30.drawString(ofToString(ttdata[min_R],1),(min_R%yy1)*pic+142,(min_R/yy1)*pic+307+pic); verdana30.drawString(ofToString(ttdata[max_R],1),(max_R%yy1)*pic+142,(max_R/yy1)*pic+307+pic); } else{ for(int tt=0;tt<16;tt++){ //iOS GUI のスイッチで、測点数値を全て表示 4X4 位置 int sokutei=(tt%4)*aaa+int(tt/4)*yy1*aaa; verdana30.drawString(ofToString(ttdata[sokutei],1),(sokutei%yy1)*pic+142,(sokutei/yy1)*pic+307+pic); } } if (botton_old!=0) ofDisableBlendMode(); } if(camdata==1) { ofDisableAlphaBlending(); //データが送られてこない場合の表示 ofSetColor(105,105,105); ofRect(142, 20, 676, 140); ofSetColor(255,210,0); cooperBlack60.drawString(" Edison---->", 100, 100); lamp_off.draw(650,20); } } //-------------------------------------------------------------- void ofApp::onPublishedService(const void* sender, string &serviceIp) { ofLog() << "Received published service event: " << serviceIp; } void ofApp::onDiscoveredService(const void* sender, string &serviceIp) { ofLog() << "Received discovered service event: " << serviceIp; } void ofApp::onRemovedService(const void* sender, string &serviceIp) { ofLog() << "Received removed service event: " << serviceIp; } //----------------以下今回は必要なし------------------------------- void ofApp::exit(){ } //-------------------------------------------------------------- void ofApp::touchDown(ofTouchEventArgs & touch){ } //-------------------------------------------------------------- void ofApp::touchMoved(ofTouchEventArgs & touch){ } //-------------------------------------------------------------- void ofApp::touchUp(ofTouchEventArgs & touch){ } //-------------------------------------------------------------- void ofApp::touchDoubleTap(ofTouchEventArgs & touch){ } //-------------------------------------------------------------- void ofApp::touchCancelled(ofTouchEventArgs & touch){ } //-------------------------------------------------------------- void ofApp::lostFocus(){ } //-------------------------------------------------------------- void ofApp::gotFocus(){ } //-------------------------------------------------------------- void ofApp::gotMemoryWarning(){ } //-------------------------------------------------------------- void ofApp::deviceOrientationChanged(int newOrientation){ }
MyGuiView.h
// // MyGuiView.h // bon // // Created by Take on 2015/02/18. // // #import <UIKit/UIKit.h> @interface MyGuiView : UIViewController @property(retain, nonatomic) IBOutlet UISlider *radiusSlider; @property(retain, nonatomic) IBOutlet UISwitch *fillSwitch; @property(retain, nonatomic) IBOutlet UISegmentedControl *Camera; @property(retain, nonatomic) IBOutlet UISegmentedControl *Devid; @property(retain, nonatomic) IBOutlet UISwitch *Temp; @end
MyGuiView.mm
// // MyGuiView.m // bon // // Created by Take on 2015/02/18. // // #import "MyGuiView.h" #include "ofxiOSExtras.h" #include "ofApp.h" @implementation MyGuiView ofApp *myApp; - (void)viewDidLoad { [super viewDidLoad]; myApp = (ofApp*)ofGetAppPtr(); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated } -(IBAction)radiusSliderHandler:(id)sender { UISlider *sliderObj = sender; myApp->sli = [sliderObj value]; } -(IBAction)Devid:(id)sender { UISlider *sliderObj = sender; myApp->div1 = [sliderObj value]; } -(IBAction)Camera:(id)sender{ //なぜ switchObj を仲介するのかわからないが、スイッチ関連はswitchObjを使えばOFに値を渡せる。 UISegmentedControl * switchObj = sender; //switchObj.selectedSegmentIndex=myApp->botton_old; //printf("switch value is - %i\n", [switchObj selectedSegmentIndex]); myApp->botton_new= switchObj.selectedSegmentIndex; } -(IBAction)Temp:(id)sender{ //UISwitchはof サンプル(iPhoneGuiExample)の toggle でも 以下の switchObj でもなぜかOK!! UISwitch * switchObj = sender; myApp->temp_sw = [switchObj isOn]; } @end
MyGuiView.xib
MyGuiView.xibは、自分で好きなようにデザインして下さい。
その他 /bin/data/ 以下に下図のような二つの画像と、fontファイルcooperBlack.ttf、frabk.ttf、verdana.ttfを入れてます。
EdisonのPythonによるプログラムソース構築
Bonjourライブラリのインストールは
http://code.google.com/p/pybonjour/からダウンロード、解凍して
cd pybonjour-1.1.1
python setup.py build
python setup.py install
でOK。
OSCライブラリのインストールは、
pip install pyOSC
でOK。
bonjourの基本プログラムは、この方を参考にさせていただきました。Python で通信 : Bonjour と TCPServer を使って|毎日の向こうに
⚪︎⚪︎⚪︎⚪︎.py
# OSC Bonjoul import mraa,time, threading,select,sys,pybonjour,socket import operator, signal from OSC import OSCClient, OSCMessage from datetime import datetime regtype = "_ofxBonjourIp._tcp" timeout = 5 resolved = [] addr="192.168.0.8" # damy!! port=1234 # damy!! # **********Bnjoul handle kill & ctrl-C************** def handleSigTERM(signum, frame): print "kill signal" exit(0) def handleCtrlC(signum, frame): print "Ctrl-C signal" exit(0) # ****************bonjour******************* def myMsgPrinter_handler(addr, tags, data, client_address): print "osc://%server%server ->" % (OSC.getUrlStr(client_address), addr), print "(tags, data): (%server, %server)" % (tags, data) # ****************OSC Start!!*************** def resolve_callback(sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtRecord): global client if errorCode != pybonjour.kDNSServiceErr_NoError: return addr = socket.gethostbyname(hosttarget) print 'Resolved service:' print ' fullname =', fullname.encode('utf_8') print ' hosttarget =', hosttarget print ' port =', port print ' IP Address =', addr resolved.append(True) # ********************ONDO i2C******************** D6T_addr = 0x0A D6T_cmd = 0x4C tdata="" client = OSCClient() client.connect( (addr, port) ) x = mraa.I2c( 6 ) #EDISON i2C PORT try: while True: x.address(D6T_addr) x.writeByte(0x4C) time.sleep(0.025) y=x.read(35) if y!=-1: for var in range(0, 16): tdata=tdata+str((y[(var*2+2)]+(y[(var*2+3)]<<8))) msg=OSCMessage("/ondo") msg.append(tdata) client.send(msg ) tdata="" except IndexError: print "I2C Data error!! Next try......." time.sleep(1) pass sys.exit(0) def browse_callback(sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain): if errorCode != pybonjour.kDNSServiceErr_NoError: return if not (flags & pybonjour.kDNSServiceFlagsAdd): print 'Service removed' return print 'Service added; resolving' resolve_sdRef = pybonjour.DNSServiceResolve(0, interfaceIndex, serviceName, regtype, replyDomain, resolve_callback) try: while not resolved: ready = select.select([resolve_sdRef], [], [], timeout) if resolve_sdRef not in ready[0]: print 'Resolve timed out' break pybonjour.DNSServiceProcessResult(resolve_sdRef) else: resolved.pop() finally: resolve_sdRef.close() # ***********************Bonjour Start!!***************************** browse_sdRef = pybonjour.DNSServiceBrowse(regtype = regtype, callBack = browse_callback) try: try: while True: ready = select.select([browse_sdRef], [], []) if browse_sdRef in ready[0]: pybonjour.DNSServiceProcessResult(browse_sdRef) except KeyboardInterrupt: pass finally: browse_sdRef.close()
動かし方
特に難しいことはありません。起動順序はiPhoneからでもEdisonからでもOKです。自分たちで勝手に相手を見つけて接続しちゃいます。