背景
Raspberry上でIOTのツールを作成しているが、Blynkと同時に他の処理(ディスプレイの表示とか、時計を使った処理とか、タイマーを使った処理とか)を行おうとすると、なかなかうまくいかない。
ArduinoでCを使って Blynkを使う時には、
1 2 3 4 5 6 |
void loop() { Blynk.run(); timer.run(); yield(); } |
のような記述で、Blynk.run()を走らせながら、他の処理もLoopとして回すことが簡単にできるのに対し、PythonでBlynkを使う時に、Blynk.run()を実行すると、この関数からは永遠に戻ってこないため、ループが作れない。
これは仕様っぽくて、確かにBlynkを使ったPythonの参考例(githubのここ)を見ても、”# Start Blynk (this call should never return)”というコメントが記載されている。要するに、行ったきりなので、何か他の事をループとしてやらせようとすると、Threadを使って、別プロセスとして起動することが必要っぽい。
Google検索で、調べてみても、海外の投稿の中に、色々やってみたけど、PythonのBlynkは、ArduinoのBlynkに比べて、そういうのが未成熟という記述があり、「代わりに、MQTTを使ったらうまくいくよ」という内容の結論で終わっていた。
追記:
別の記事を見ていたら、このサイトに、Threadを使って、BlynkをPythonから使う例が掲載されていた。今晩試してみることにする。タイマーでの1秒毎の処理と、BlynkのVirtual Writeをthreadで走らせる形。
うまく出来た。
このサイトのやり方を真似て、threadingを使ったら、すぐにうまく出来た。なぁーんだ。
t2のThreadがユーザープログラムなので、ここで好きなプログラムを書けば、Blynk.run()が動いている状態で、問題なく動作させることができる。sleep()で待とうが、グリグリとloopを回そうが、自由にthreadで動かせる。
ここでは、一秒毎に、GPIOをトグルして、かつVirtual Pinに ms() //1000の値を送ることが出来ている。当然、スマホのBlynkアプリからのVirtual Writeに対しても問題なく反応している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#!/usr/bin/python3 # using thread with another way # import BlynkLib import time from time import sleep import RPi.GPIO as GPIO import threading BLYNK_AUTH = 'b7*****************************1c' GPIO.setmode(GPIO.BCM) GPIO.setup(24, GPIO.OUT) pin24 = True blynk = BlynkLib.Blynk(BLYNK_AUTH) def my_user_task(): global pin24 value=0 while True: blynk.virtual_write(4, str(value)) value += 1 blynk.virtual_write(5, time.ticks_ms() //1000) if pin24 == True: pin24 = False else: pin24 = True GPIO.output(24, pin24) sleep(1) def startBlynk(): blynk.run() # never returns @blynk.VIRTUAL_WRITE(1) def my_write_handler(value): pass @blynk.VIRTUAL_WRITE(0) def my_write_handler(value): if value == '1': GPIO.output(24, True) else: GPIO.output(24, False) if __name__ == "__main__": th1 = threading.Thread(name='blynk', target=startBlynk) th2 = threading.Thread(name='user_task', target=my_user_task) th1.start() #start Blynk. blynk.run() never returns but it does not block the user task. th2.start() |