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のソーラーパネルで賄えないものなのか?
