GWから作り始めているベランダビオトープ棚、システムを早く組まねばーっと思ってまごまごしてたら、お古のバッテリーとチャージコントローラーを手に入れてしまいました。
ソーラーパネルのみ(蓄電装置なし)で暑いときだけ、ファン・ポンプを稼働させるつもりでしたが、手に入れたからには蓄電込みのシステムにしようと思い、現状で、構想通りのシステムはまだ組めていませんが、最低限の動作はしているので、記事にします。
■システム
◇構成
ATOM LiteをMicroPythonで制御して以下の装置を動作させています。
・温度センサ×1
・水検知センサ×1
・水ポンプ×1
・ファン×1
◇動作
・バッテリー電圧を監視し、過放電防止
・ファンとポンプはPWM制御でパワーコントロール
・ポンプ稼働時は水センサで水位確認し、空運転防止(フロースイッチ)
・WIFIで時刻を取得し、ポンプをスケジュール稼働
・外気温によってファンのパワー調整
・稼働状況をWEBサーバーにロギング
・サーバーからプログラム更新可能
■プログラム
◇サーバーからのプログラム更新
一定時間ごとに、サーバーに新規プログラムがないか確認して、あればプログラムを更新するようにしてます。(詳細はこちら)
main.pyからprogram.pyのmain関数をループし、一定間隔で更新プログラムがあるか確認します。
main.py
import machine,neopixel import network import urequests import utime np = neopixel.NeoPixel(machine.Pin(27, machine.Pin.OUT), 1) np[0] = (10, 0, 0) #red np.write() #URLs for the updates upd_url = "http://hogehoge/get_script.php?file=program.py" del_url = "http://hogehoge/delete_script.php?file=program.py" def connect_wifi(): print('connecting to network...',end=' ') sta_if = network.WLAN(network.STA_IF) if not sta_if.isconnected(): sta_if.active(True) sta_if.connect('SSID','PASSWORD') #要変更 st = utime.time() while not sta_if.isconnected(): if utime.time()-st > 10: #timeout print('cannot connect wifi') return False utime.sleep(0.1) print('connected!') else: print('already connecting') #print('network config:', sta_if.ifconfig()) return True def check_for_updates(): print('Checking if the file has been updated...') if not connect_wifi(): return False try: response = urequests.get(upd_url) x = response.text.strip() if x == "FAIL": print('no updates available.') return False else: print('update available') return True except: print('unable to reach internet') return False def program_update(): print('Downloading update files...') #download the update and overwrite program.py response = urequests.get(upd_url) x = response.text.strip() if x != "FAIL": #download twice and compare for security x = response.text response = urequests.get(upd_url) if response.text == x: f = open("program.py","w") f.write(response.text) f.flush() f.close() print('done') urequests.get(del_url) print('reboot now') machine.deepsleep(5000) def main(): program_error = 0 while True: if check_for_updates(): program_update() program_error = 0 try: import program program.main() except: print('PROGRAM RUN ERROR') np[0] = (10, 10, 0) #yellow np.write() utime.sleep(60) if __name__ == '__main__': main()
◇時間外ではスリープ
時刻を取得して、9時〜18時以外はディープスリープします。
import time def set_localtime(): import ntptime utime.sleep(1) # wait connect to NTPserver ntptime.settime() tm = utime.localtime(utime.time()+9*3600) return tm def main(looptime=1800): print('start program') global stopped_mainloop import main pwm2.duty(0) #for error wifi_connected = False if main.connect_wifi(): log_data() tm = set_localtime() tm_hour = tm[3] tm_min = tm[4] wifi_connected = True else: tm_hour = 12 tm_min = 0 if tm_hour < 9 or tm_hour > 18: print('time is off-duty. start deepsleep...') for gp in [19,21,22,23,25,26,32,33,34]: machine.Pin(gp).init(pull=None) np[0] = (0, 0, 0) np.write() machine.deepsleep(looptime*1000)
なお、deepsleepに入る前にPinをリセットしてるのは、回路によってはプルアップ抵抗による電力消費を節約するためだとかで、なんとなく書いています。
◇外気温とバッテリー電圧のロギング
稼働した時に外気温と電圧をサーバーにアップします。
アップ先は、自前のWEBサービスを利用。このグラフを眺めるだけで面白い。
温度センサーについてはこちら。
import machine adc0 = machine.ADC(machine.Pin(33)) adc0.atten(machine.ADC.ATTN_11DB) adc0_factor = 3.6 / 65535 * 5.5 def get_batt_vol(): return adc0.read_u16()*adc0_factor adc1 = machine.ADC(machine.Pin(32)) adc1.atten(machine.ADC.ATTN_2_5DB) def get_temp(): val = 0.0 for i in range(100): val += adc1.read() utime.sleep(0.001) val = val/100 vol = val * 1.40/4095+0.03 temp = (vol - 0.6)*100 return temp def log_data(append_data=''): batt_vol = get_batt_vol() temp = get_temp() url = 'http://webapps.tiblab.net/device/alive-monitor/?p=input-XXXXXXXX' data = '&d1='+str(batt_vol)+'&d2='+str(temp)+append_data ret = urequests.get(url+data) if ret.text[:1] == '1': print('success send data:'+data) return True else: print('fail send data:'+data) return False def main(looptime=1800): print('start program') global stopped_mainloop import main wifi_connected = False if main.connect_wifi(): log_data() #omit
◇ファンのパワーコントロール
ファンとポンプのコントロールは、別にスレッドを立てて、マルチスレッド方式にしました。それが必須の事由はないのですが、その方がコードを分離できて書きやすくなるので(不具合が起きた時のデバッグがしづらくなるかもでずが)。
ファンは、PWM制御で、外気温が35℃以上で40%のパワーで回り始め、温度が1℃上がるごとに10%パワーを上げるようにしました。
ついでにファンの稼働状況をサーバーにアップしてます。
import machine pwm1 = machine.PWM(machine.Pin(25)) pwm1.duty(0) def fan_control(): global stopped_fan_control print('start fan control') is_spinning = False while True: batt_vol = get_batt_vol() temp = get_temp() if not is_spinning: if batt_vol > 13.0 and temp > 35: power = min(max((temp-35.0)*0.1,0.4),1.0) pwm1.duty(int(1023*power)) log_data('&d3='+str(power)) is_spinning = True print('fan start') else: if batt_vol < 12.0 or temp < 35: pwm1.duty(0) log_data('&d3=0.0') is_spinning = False print('fan stop') if stopped_mainloop: break utime.sleep(1) stopped_fan_control = True print('stopped fan control') stopped_mainloop = False def main(looptime=1800): print('start mainloop') start_time = utime.time() while True: #main task if(utime.time()-start_time > looptime): stopped_mainloop = True break print('stopped mainloop') print('waiting thread stop') while True: if stopped_fan_control: break utime.sleep(0.1) print('fin')
◇ポンプの時間稼働
ポンプは、朝と夕方の2回、5分間稼働させてます。PWM制御でパワーは必要最低限になるように、何回か試して5%にしました。
ポンプは水がない状態で使用すると故障するらしいので、水検知センサにより空運転を防止してます。
水センサについてはこちら。
やってみて分かった課題としては、指定した時刻の時に動くようにしましたが、インターネット回線が意外と不安定で、その5分間が接続できていないと時刻が取得できずポンプが稼働しません。
なので、稼働したかどうかのログをサーバーに残して、未実施なら実施する処理が要るなと思いました。
stopped_pump_cont = True def pump_control(): global stopped_pump_cont print('start pump control') stopped_pump_cont = False while True: tm = utime.localtime(utime.time()+9*3600) tm_hour = tm[3] tm_min = tm[4] if ((tm_hour==10 or tm_hour==17) and tm_min < 5 and water_pin.value()): pwm0.duty(int(1023*0.05)) else: pwm0.duty(0) if stopped_mainloop: break utime.sleep(1) stopped_pump_cont = True print('stopped pump control')
プログラム全体、回路図とかは次回以降。。。^^;
構想としては、温度センサと水検知センサ、ファンを1つずつ追加する予定です。
懸念点としては、バッテリー電圧の推移を見ると、晴れの日が続いていても電圧は下降の一途で、十分な充電ができていないこと。
なんで、2週間に一回程度、フル充電させる必要があります。
んー、パネルは壁に立てかけているだけで場所はよくなんだと思いますが、直射日光は当たる場所だし、ファン(3W)はほとんど回っていないし、ポンプ(5W)は一日10分回ってる時間はそんなに長くないのに、20Wのソーラーパネルで賄えないものなのか?