LoginSignup
0
0

Inkbird IBS-TH1 PLUSの値をESP-WROOM-32でスプレッドシートへ記録

Last updated at Posted at 2023-07-12

はじめに

Inkbird IBS-TH1 PLUSの値をBeagleBone Blackでスプレッドシートへ記録を元にBeagleBone Black+python3 からESP-WROOM-32+micropythonに変更した時の記録です。

使用機材

1.ESP32に Micropython を焼きます

本家 https://docs.micropython.org/en/latest/esp32/tutorial/intro.html#esp32-intro

pip insttall esptool

ESP32をPCに繋いだら/dev/ttyUSB0に出てくるのを確認。書き込み権限も確認。

BOOTボタン押しながらENボタン押してFirmware downloadモードにします

esptool.py --port /dev/ttyUSB0 erase_flash 
esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash -z 0x1000 esp32-20230426-v1.20.0.bin

1.5 シリアルプロンプト

sudo apt install picocom
picocom /dev/ttyUSB0 -b115200

これでmicropythonのプロンプトが見えたらOKです。

2. adfruit-ampy インストール

ファイル転送のためだけにインストールします。

pip install adafruit-ampy

ファイル転送のコマンドは以下の通り

ampy -p /dev/ttyUSB0 put main.py

3. ESP32 のBLEでInkbirdのセンサ値を取得

bluepyはmicropythonにないため、ubluetoothで作成します。BLE Central RoleGATT Clientを実装。BLE advertiserBLE scannerGATT Serverはしない方針です。

処理の流れは以下の通り。

  1. BLE ON
  2. BLE Connect
  3. BLE READ(GATT Client)
  4. BLE disconnect
  5. BLE OFF
main.py
# config 
PERIPHERAL_MAC_ADDRESS=b'\xFF\xFF\xFF\xFF\xFF\xFF'

##
import ubluetooth
import utime
import ustruct

## event codes は https://docs.micropython.org/en/latest/library/bluetooth.html#event-handling から必要なものだけ
_IRQ_PERIPHERAL_CONNECT = (7)
_IRQ_PERIPHERAL_DISCONNECT = (8)
_IRQ_GATTC_READ_RESULT = (15)
_IRQ_GATTC_READ_DONE = (16)


## 1.BLE ON
ble=ubluetooth.BLE()
ble.active(True)

# setting IRQ
def bt_irq(event, data):
    if event == _IRQ_PERIPHERAL_CONNECT:
        # A successful gap_connect().
        conn_handle, addr_type, addr = data
        global conn_state
        conn_state = 0
        global handle
        handle=conn_handle
    elif event == _IRQ_PERIPHERAL_DISCONNECT:
        # Connected peripheral has disconnected.
        conn_handle, addr_type, addr = data
        global conn_state
        conn_state = -2
    elif event == _IRQ_GATTC_READ_RESULT:
        # A gattc_read() has completed.
        conn_handle, value_handle, char_data = data
        global temp
        global humid
        (temp, humid, unknown1, unknown2, unknown3) = ustruct.unpack('<hhBBB', char_data)
    elif event == _IRQ_GATTC_READ_DONE:
        # A gattc_read() has completed.
        # Note: Status will be zero on success, implementation-specific value otherwise.
        conn_handle, value_handle, status = data
        global rstatus
        rstatus=status

ble.irq(bt_irq)

##  2. BLE connect
addr_type=0 
conn_time = 30
# conn_state  0:connected , -1:connecting  , -2:disconnected
conn_state=-1
ble.gap_connect(addr_type, PERIPHERAL_MAC_ADDRESS)
while( conn_state != 0 ):
    print("BLE connecting ..",conn_time)
    if( conn_state == -2):
        conn_state =-1
        ble.gap_connect(addr_type, PERIPHERAL_MAC_ADDRESS)
        
    conn_time = conn_time -1
    if(conn_time < 0):
        break
    utime.sleep_ms(1000)

if( conn_state == 0):
    ### 3. BLE read ( GATT Client )
    value_handle=0x2d 
    rstatus=-1
    ble.gattc_read(handle,value_handle)
    ### wait read 
    while(rstatus!=0):
	    utime.sleep_ms(2000)

    ### output
    print(temp/100 , humid/100)

    ## 4.BLE disconnect 
    ble.gap_disconnect(handle)

# 5. BLE OFF
ble.active(False)

Inkbird IBS-TH1PLUS のvalue_handle は0x2d です。

PERIPHERAL_MAC_ADDRESS へ InkbirdのMACアドレスを入力した後,ファイル転送&実行してInkbird の温度と同じであれば動作確認完了です。

$ ampy -p /dev/ttyUSB0 put main.py
$ picocom /dev/ttyUSB0 -b115200
>>> (Ctrl-Dで soft reboot)
27.24 48.11
MicroPython v1.20.0 on 2023-04-26; ESP32 module with ESP32
Type "help()" for more information.
>>> 

4.ESP32 から WLAN経由でスプレッドシートにセンサ値を書き込み

スプレッドシートにセンサ値を書き込むGASスクリプトをWebAppとして公開

前回の記事のスクリプトをmicropythonでクエリパラメータをPOSTする方法が分からなかったのでクエリーパラメータからJSONパラメータへ変更する。

postSensorData.gs
var book = SpreadsheetApp.getActiveSpreadsheet();

//PostされたJSONデータを受け取り
function doPost(e){

  var parameter = JSON.parse(e.postData.getDataAsString());

  var data = [      
    parameter.Date_Master, // マスター日時     
    parameter.Date, // 測定日時    
    parameter.Temperature, // 気温    
    parameter.Humidity, // 湿度    
    parameter.Light, // 照度    
    parameter.UV, // UV    
    parameter.Pressure, // 圧力    
    parameter.Noise, // 騒音    
    parameter.BatteryVoltage, // 電池電圧    
    new Date(), // アップロード終了時刻    
  ];
  //取得したデータをログに記載
  Logger.log(new Date());
  //スプレッドシートへのデータ行書き込み
  addData(parameter.DeviceName, data);

  //返り値
  var output = ContentService.createTextOutput();
  output.setMimeType(ContentService.MimeType.JSON);
  output.setContent(JSON.stringify({ message: "success!" }));
  return output;
}

//スプレッドシートへのデータ行書き込み
function addData(sheetName, data){
  var sheet = book.getSheetByName(sheetName);
  sheet.appendRow(data);

}

WebAppへPOSTするスクリプトの作成

WLANの接続処理を追加する。リファレンスそのままです。

全体の処理の流れは以下の通り。

  1. BLE ON
  2. BLE Connect
  3. BLE READ(GATT Client)
  4. BLE disconnect
  5. BLE OFF
  6. WLAN connect
  7. POST data
  8. WLAN disconnect
main.py
# config
PERIPHERAL_MAC_ADDRESS=b'\xFF\xFF\xFF\xFF\xFF\xFF'
WEB_APP_URL='https://script.google.com/macros/s/******/exec'
DEVICE_NAME='****'
WLAN_SSID='******'
WLAN_PASSWD='******'

##
import ubluetooth
import utime
import ustruct

## event codes は https://docs.micropython.org/en/latest/library/bluetooth.html#event-handling から必要なものだけ
_IRQ_PERIPHERAL_CONNECT = (7)
_IRQ_PERIPHERAL_DISCONNECT = (8)
_IRQ_GATTC_READ_RESULT = (15)
_IRQ_GATTC_READ_DONE = (16)

## 1.BLE ON
ble=ubluetooth.BLE()
ble.active(True)

# setting IRQ
def bt_irq(event, data):
    if event == _IRQ_PERIPHERAL_CONNECT:
        # A successful gap_connect().
        conn_handle, addr_type, addr = data
        global conn_state
        conn_state = 0
        global handle
        handle=conn_handle
    elif event == _IRQ_PERIPHERAL_DISCONNECT:
        # Connected peripheral has disconnected.
        conn_handle, addr_type, addr = data
        global conn_state
        conn_state = -2
    elif event == _IRQ_GATTC_READ_RESULT:
        # A gattc_read() has completed.
        conn_handle, value_handle, char_data = data
        global temp
        global humid
        (temp, humid, unknown1, unknown2, unknown3) = ustruct.unpack('<hhBBB', char_data)
    elif event == _IRQ_GATTC_READ_DONE:
        # A gattc_read() has completed.
        # Note: Status will be zero on success, implementation-specific value otherwise.
        conn_handle, value_handle, status = data
        global rstatus
        rstatus=status

ble.irq(bt_irq)

##  2. BLE connect
addr_type=0 
conn_time = 30
# conn_state  0:connected , -1:connecting  , -2:disconnected
conn_state=-1
ble.gap_connect(addr_type, PERIPHERAL_MAC_ADDRESS)
while( conn_state != 0 ):
    print("BLE connecting ..",conn_time)
    if( conn_state == -2):
        conn_state =-1
        ble.gap_connect(addr_type, PERIPHERAL_MAC_ADDRESS)
        
    conn_time = conn_time -1
    if(conn_time < 0):
        break
    utime.sleep_ms(1000)

if( conn_state == 0):
    ### 3. BLE read ( GATT Client )
    value_handle=0x2d 

    rstatus=-1
    ble.gattc_read(handle,value_handle)
    ### wait read 
    while(rstatus!=0):
	    utime.sleep_ms(2000)

    ### output
    print(temp/100 , humid/100)


    ## 4.BLE disconnect 
    ble.gap_disconnect(handle)

# 5. BLE OFF
ble.active(False)

###################################
# 6.WLAN connect

def do_connect():
    import network
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('connecting to network..')
        wlan.connect( WLAN_SSID, WLAN_PASSWD)
        while not wlan.isconnected():
            pass
    print('network config:', wlan.ifconfig())


do_connect()
 
# 7. POST data
import urequests
import ujson

# upload to the spreadsheet
data = {
    'DeviceName': DEVICE_NAME,
    'Date_Master': '',
    'Date': '',
    'SensorType': '' ,
    'Temperature': str(temp/100),
    'Humidity': str(humid/100),
    'Light': '',
    'UV': '',
    'Pressure': '',
    'Noise': '',
    'BatteryVoltage': ''
 }

response = urequests.post( WEB_APP_URL, data=ujson.dumps(data))
response.close()

# 8.WLAN disconnect
wlan.disconnect()
wlan.active(False)

PERIPHERAL_MAC_ADDRESS へ InkbirdのMACアドレスを、
WEB_APP_URL へ GASのWebAPPのUrl を、
deviceName へ Googleスプレッドシートのシート名を
WLAN_SSID へ ローカルWifiのSSIDを、
WLAN_PASSWDへ ローカルWifiのパスワードを、それぞれ入力します。

その後、以下のコマンドを実行してスプレッドシートに値が書き込まれていたら動作確認完了です。

$ ampy -p /dev/ttyUSB0 put main.py
$ picocom /dev/ttyUSB0 -b115200
>>> (Ctrl-Dで soft reboot)
27.75 48.71
connecting to network..
network config: ('192.168.10.115', '255.255.255.0', '192.168.10.1', '192.168.10.1')
MicroPython v1.20.0 on 2023-04-26; ESP32 module with ESP32
Type "help()" for more information.
>>> 
 

5. ESP32 でスケジュール実行

cronは無いので while loop とsleep で実装
(2023-08-20 追記) while loop だと urequests.py がエラーでおちるため、毎回再起動させる方針へ変更

  1. BLE ON
  2. BLE Connect
  3. BLE READ(GATT Client)
  4. BLE disconnect
  5. BLE OFF
  6. WLAN connect
  7. POST data
  8. WLAN disconnect
  9. Sleep
  10. reset
main.py
# config
PERIPHERAL_MAC_ADDRESS=b'\xFF\xFF\xFF\xFF\xFF\xFF'
WEB_APP_URL='https://script.google.com/macros/s/******/exec'
DEVICE_NAME='****'
WLAN_SSID='******'
WLAN_PASSWD='******'

##
import ubluetooth
import utime
import ustruct

## event codes は https://docs.micropython.org/en/latest/library/bluetooth.html#event-handling から必要なものだけ
_IRQ_PERIPHERAL_CONNECT = (7)
_IRQ_PERIPHERAL_DISCONNECT = (8)
_IRQ_GATTC_READ_RESULT = (15)
_IRQ_GATTC_READ_DONE = (16)



## 1.BLE ON
ble=ubluetooth.BLE()
ble.active(True)

# setting IRQ
def bt_irq(event, data):
    if event == _IRQ_PERIPHERAL_CONNECT:
        # A successful gap_connect().
        conn_handle, addr_type, addr = data
        global conn_state
        conn_state = 0
        global handle
        handle=conn_handle
    elif event == _IRQ_PERIPHERAL_DISCONNECT:
        # Connected peripheral has disconnected.
        conn_handle, addr_type, addr = data
        global conn_state
        conn_state = -2
    elif event == _IRQ_GATTC_READ_RESULT:
        # A gattc_read() has completed.
        conn_handle, value_handle, char_data = data
        global temp
        global humid
        (temp, humid, unknown1, unknown2, unknown3) = ustruct.unpack('<hhBBB', char_data)
    elif event == _IRQ_GATTC_READ_DONE:
        # A gattc_read() has completed.
        # Note: Status will be zero on success, implementation-specific value otherwise.
        conn_handle, value_handle, status = data
        global rstatus
        rstatus=status

ble.irq(bt_irq)

##  2. BLE connect
addr_type=0 
conn_time = 30
# conn_state  0:connected , -1:connecting  , -2:disconnected
conn_state=-1
ble.gap_connect(addr_type, PERIPHERAL_MAC_ADDRESS)
while( conn_state != 0 ):
    print("BLE connecting ..",conn_time)
    if( conn_state == -2):
        conn_state =-1
        ble.gap_connect(addr_type, PERIPHERAL_MAC_ADDRESS)
        
    conn_time = conn_time -1
    if(conn_time < 0):
        break
    utime.sleep_ms(1000)

if( conn_state == 0):
    ### 3. BLE read ( GATT Client )
    value_handle=0x2d 

    rstatus=-1
    ble.gattc_read(handle,value_handle)
    ### wait read 
    while(rstatus!=0):
        utime.sleep_ms(2000)

    ### output
    print(temp/100 , humid/100)


    ## 4.BLE disconnect 
    ble.gap_disconnect(handle)

# 5. BLE OFF
ble.active(False)

###################################
# 6.WLAN connect

def do_connect():
    import network
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('connecting to network..')
        wlan.connect( WLAN_SSID, WLAN_PASSWD)
        while not wlan.isconnected():
            pass
    print('network config:', wlan.ifconfig())


do_connect()

# 7. POST data
import urequests
import ujson

# upload to the spreadsheet
data = {
    'DeviceName': DEVICE_NAME,
    'Date_Master': '',
    'Date': '',
    'SensorType': '' ,
    'Temperature': str(temp/100),
    'Humidity': str(humid/100),
    'Light': '',
    'UV': '',
    'Pressure': '',
    'Noise': '',
    'BatteryVoltage': ''
 }

response = urequests.post( WEB_APP_URL, data=ujson.dumps(data))
response.close()

# 8.WLAN disconnect
wlan.disconnect()
wlan.active(False)


# 9.Sleep
sleep_time= 30*60      #30 min
while(sleep_time > 0):
    print(sleep_time)
    sleep_time=sleep_time-1
    utime.sleep(1)  # 1sec 


# 10.reset
import machine
machine.reset()

その他

micropython のexampleが動かなくなっていたため、調査しながら作ったら、とてもスクリプトっぽいコードになってしまいました。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0