Ambientでグラフ化 | virt_flyのブログ

virt_flyのブログ

フライトシミュレーターソフトのFlightGearで仮想飛行を楽しむブログです。

Raspberry Pi Pico W Ambient グラフ表示

↑Raspberry Pi Oico Wからセンサー値を送信、クラウドサービスのAmbientでグラフ化

 

Pico Wでデータ可視化クラウドサービスを利用

 

前回は、Raspberry Pi Pico Wを使って、温湿度センサーの測定値をOLEDに表示するとともに、せっかくあるWi-Fi機能を利用したいと、測定値のWEBページ表示を試しました。

 

Webページ表示と言っても、Pico WをWebサーバーにしてイントラネット上のPCのブラウザで値を確認しようとするものでした。

 

ここはやはりWi-Fi機能をいかして、インターネット上のクラウドサービスを利用すべしと測定値の可視化を試すことにしました。

 

■Ambientで測定値のCSVファイル化も

 

Raspberry Pi Pico Wで温湿度を測定しAmbientに送信

↑温湿度センサー(Si7021)の値をOLED、Webページ、Ambientで表示するRaspberry Pi Pico W

 

データをグラフ表示など可視化するクラウドサービスはいろいろあるのでしょうが、使うのは以前にも使用したことのあるAmbient。運よくまだ登録はいきていました。

 

恥ずかしながら、他により便利なサービスがあるのかも知れませんが、一応グラフ化できれば良し、生のデータ自体もCSVファイルとしてダウンロードできるのなら、後でいくらでも加工できろのだからそれで充分と思っています。

 

CSVファイルインポート設定画面

↑Ambientでリアルタイムに受信して時刻を付したたデータはCSVファイルにDL可能

 

多少タイムラグはあるでしょうが、測定値を受信する際にAmbientの方で順次時刻も記録してくれますから、Pico W側で測定時刻をいちいち付して送信する必要がないのも楽です。

 

■Ambientの使い方ープログラミングは生成AIで

 

Ambientの使い方は、おおよそ次の通りです。

①ユーザー登録(無料)

②チャネル生成

③マイコン側プログラミング

④データー送信

⑤可視化(グラフ化)

 

登録(無料)やチャネルの作成、グラフの設定は簡単ですので、具体的には当該サイトをご覧になればよいでしょう。問題になるのは、Ambient用のmicropythonプログラムの書き方です。実例をネットで探すのもよいですが、生成AIに書かせてもよいのでは。私はそうしました。生成AIも進化したもので、今ではプログラミングなら全面的に任せられます(注参照)。

 

今回のプログラムは次の通りです。少々整理しました。

 

import network
import socket
import time
import urequests
import gc
from machine import Pin, I2C
from ssd1315 import SSD1315_I2C

# ===== Wi-Fi =====
SSID = "Wi-Fiネットワーク名"
PASSWORD = "パスワード"

# ===== Ambient =====
AMBIENT_CHANNEL_ID = "チャネルID"  #←数値です ””は取る
AMBIENT_WRITE_KEY = "ライトキー"

# ===== I2C =====
i2c_oled = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
i2c_sensor = I2C(1, scl=Pin(3), sda=Pin(2), freq=400000)

oled = SSD1315_I2C(128, 64, i2c_oled, addr=0x3C)
SENSOR_ADDR = 0x40

# ===== センサー =====
def read_si7021():
    try:
        i2c_sensor.writeto(SENSOR_ADDR, b'\xE3')
        t = i2c_sensor.readfrom(SENSOR_ADDR, 2)
        temp = (175.72 * (t[0]<<8 | t[1]) / 65536) - 46.85

        i2c_sensor.writeto(SENSOR_ADDR, b'\xE5')
        h = i2c_sensor.readfrom(SENSOR_ADDR, 2)
        hum = (125.0 * (h[0]<<8 | h[1]) / 65536) - 6

        return temp, hum
    except:
        return None, None

# ===== OLED =====
def draw(temp, hum, ip):
    oled.fill(0)
    oled.text("Env Monitor", 10, 0)
    oled.text("Temp:{:.1f}C".format(temp), 0, 18)
    oled.text("Hum :{:.1f}%".format(hum), 0, 34)
    oled.text(ip, 0, 52)
    oled.show()

# ===== Wi-Fi接続 =====
wlan = network.WLAN(network.STA_IF)
wlan.active(True)

def ensure_wifi():
    if wlan.isconnected():
        return True
    wlan.connect(SSID, PASSWORD)
    for _ in range(10):
        if wlan.isconnected():
            return True
        time.sleep(1)
    return False

print("connecting wifi...")
ensure_wifi()
ip = wlan.ifconfig()[0]
print("wifi ok:", ip)

# ===== Ambient送信 =====
def send_ambient(temp, hum):
    if not ensure_wifi():
        return
    try:
        url = "https://ambidata.io/api/v2/channels/{}/data".format(AMBIENT_CHANNEL_ID)
        data = {"writeKey": AMBIENT_WRITE_KEY, "d1": temp, "d2": hum}
        r = urequests.post(url, json=data)
        print("ambient:", r.status_code)
        r.close()
        gc.collect()
    except Exception as e:
        print("ambient error:", e)

# ===== Webサーバー =====
srv = socket.socket()
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(('0.0.0.0', 80))
srv.listen(1)
srv.settimeout(0.2)

latest_temp = 0
latest_hum = 0

def handle_web():
    try:
        cl, addr = srv.accept()
        cl.settimeout(1)

        body = """<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="5">
</head>
<body style="text-align:center;font-family:sans-serif;margin-top:40px;">
<h1>環境モニター</h1>
<h2>温度: {:.1f} ℃</h2>
<h2>湿度: {:.1f} %</h2>
<p>IP: {}</p>
</body>
</html>
""".format(latest_temp, latest_hum, ip)

        response = "HTTP/1.1 200 OK\r\n"
        response += "Content-Type: text/html\r\n"
        response += "Connection: close\r\n"
        response += "Content-Length: {}\r\n\r\n".format(len(body))
        response += body

        cl.send(response)
        cl.close()

    except:
        pass

# ===== メインループ =====
last_sensor = 0
last_send = 0

while True:
    now = time.time()

    # センサー更新(2秒)
    if now - last_sensor > 2:
        t, h = read_si7021()
        if t is not None:
            latest_temp = t
            latest_hum = h
            draw(t, h, ip)
        last_sensor = now

    # Ambient送信(60秒)
    if now - last_send > 60:
        send_ambient(latest_temp, latest_hum)
        last_send = now
        time.sleep(2)

    # Web応答
    handle_web()
    time.sleep(0.05)

 

プログラムは、CatGPTの助けを借りて作成しています。

 

 

 

 

注)生成AIが生成したコードには著作権の問題があります。通常、ChatGPTやCopilotの生成物はユーザーに著作権があるとされます。しかし、そうしたコードのソースとの関係で著作権侵害が起こりえる可能性もあります。したがって、個人利用の範囲にとどめ、商業利用はもとより公開も慎重であるべきと考えられます。ユニークなアルゴリズムだったりすれば著作権は守られてしかるべきですが、もちろん、ごく一般的な記述、ありふれた実装パターンまで制限されることはありえません。そんなことになれば、一切プログラムは書けなくなってしまいますから、その範囲であれば問題ないことは自明です。生成AIにプログラミングさせたのなら、生成AIにありふれた実装パターンであるかたずねてみたらどうでしょう。