【IoTプログラミング入門】Windows PCで作る、Python、Sqlite3を使ったデータ収集する方法

Python
YOU
YOU

センサからのデータを、PCに取り込んで、データ解析したいんだけど、なにからやればいいのかな。

けんろう
けんろう

まずは、センサデバイスからデータを取り込み、データベースに書き込むところからはじめてみよう。一度、データベースに格納すれば、そのデータを並び替えたり、加工したりとデータ解析に必要な環境がそろうよ。

今回は、センサデバイスから、シリアル通信でデータを取り込み、データベースに格納する方法を紹介します。

スポンサーリンク

これから作るアプリについて

構成

センサーデバイス(M5 ATOM):テストデータをシリアル通信でPCへ送信。

PC:このシリアルデータを受信して、Sqlite3で構築したデータベースに書き込む。

PC:確認用ソフトで、書きこんたデータを読み出す。

本アプリ仕様

シリアル通信仕様

以下のデータが、”,”を挟んで送られてくる
・取得時間(センサー側)
・受信データ(1バイト目がメッセージID、2バイト目以降がデータ)

例は、以下です。
472095,82,0,0,80,0,

テーブル仕様は、以下です。

    # テーブルの作成
    # テーブル名:mytable
    # テーブルデータ1:id 格納する毎にインクリメントする番号
    # テーブルデータ2:Rcv_time 本プログラムがシリアルデータを受信したUNIX時間
    # テーブルデータ3:device_time シリアルデータ送信元がセンサ情報を取得した時間(フリーランタイマを想定)
    # テーブルデータ4:message_id シリアルデータのメッセージID
    # テーブルデータ5:rcv_data センサが送っているシリアルデータ全て(device_time、message_id、data)

PCアプリ

サンプルコード

PC側につなぐシリアル通信用のCOMは、ご自身のPCにあったものを指定してください。

デバイスマネージャで、調べることができます。


#!usr/bin/env python
# -*- coding: utf-8 -*-

import serial
import time
import sqlite3
import os

ser = serial.Serial('COM3',115200,timeout=None)         # COM3は、例です。シリアル通信を繋いだCOMポート番号を指定すること

def func1():

    rcvdata = []

    # データベースファイルのパス
    dbpath1 = 'db_serial.sqlite'

    # データベース接続とカーソル生成
    connection1 = sqlite3.connect(dbpath1)

    # 自動コミットにする場合は下記を指定(コメントアウトを解除のこと)
    #connection1.isolation_level = None
    cursor1 = connection1.cursor()

    while True:

        rcvdata.clear()

        # STEP1: データ受信
        received = ser.readline()

        # STEP2: チェック前処理
        # STEP2-1: UTF-8に変換
        received_str = received.decode("utf-8")
        # STEP2-2: 受信データから、余分なデータ(\n、\r)を取り除く
        received_split = received_str.rstrip("\n")
        received_split = received_split.rstrip("\r")
        # STEP2-3: 受信データを分割(”,”毎にデータを分割)
        received_split2 = received_split.split(",")

        # 受信データを表示する
        print(received_split, end='')

        # STEP2-4: 分割した受信データを、後から加工しやすいように個別データに入れなおす
        for i in received_split2:
            rcvdata.append(i)

        # STEP3: データベースに格納
        para0 = time.time()     # タイムスタンプ(UNIX時間)
        para1 = rcvdata[0]   # 取得時間(センサー側)
        para2 = rcvdata[1]   # メッセージID
        para3 = received_split  # 受信データ(とりあえず受信データ全てを記憶する)

        setdata = [para0, para1, para2, para3]
        sql = "INSERT INTO mytable (Rcv_time, device_time, message_id, rcv_data) VALUES (?, ?, ?, ?)"
        cursor1.execute(sql, setdata)
        connection1.commit()

        print("\n")

if __name__ == "__main__":

    # データベースファイルのパス
    dbpath = './db_serial.sqlite'

    # データベース接続
    connection = sqlite3.connect(dbpath)

    # 自動コミットにする場合は下記を指定(コメントアウトを削除)
    #connection.isolation_level = None
    cursor = connection.cursor()

    # テーブルの作成
    # テーブル名:mytable
    # テーブルデータ1:id 格納する毎にインクリメントする番号
    # テーブルデータ2:Rcv_time 本プログラムがシリアルデータを受信したUNIX時間
    # テーブルデータ3:device_time シリアルデータ送信元がセンサ情報を取得した時間(フリーランタイマを想定)
    # テーブルデータ4:message_id シリアルデータのメッセージID
    # テーブルデータ5:rcv_data センサが送っているシリアルデータ全て(device_time、message_id、data)

    sql = "CREATE TABLE IF NOT EXISTS mytable (id INTEGER PRIMARY KEY, Rcv_time REAL, device_time INTEGER, message_id TEXT, rcv_data TEXT)"
    cursor.execute(sql)

    # 保存を実行(忘れると保存されないので注意)
    connection.commit()

    # 接続を閉じる
    connection.close()

    func1()

テストデータの作成(M5ATOM側)

M5ATOMで、今回のテストデータを作成します。

サンプルコード

#include "M5Atom.h"
#include "time.h"

void setup() {

  M5.begin();
  delay(10);
  Serial.begin(115200);

}

void loop() {
#define MAX_NUM1 5
  uint8_t list1[] =  {0x01,0x88,0x12,0xCB,0x00};
#define MAX_NUM2 2
  uint8_t list2[] =  {0xBA,0xBA};
#define MAX_NUM3 5
  uint8_t list3[] =  {0x82,0x00,0x00,0x80,0x00};
#define MAX_NUM4 2
  uint8_t list4[] =  {0xDA,0xDA};
#define MAX_NUM5 2
  uint8_t list5[] =  {0x3A,0x3A};
#define MAX_NUM6 5
  uint8_t list6[] =  {0x82,0x00,0x00,0x80,0x00};
#define MAX_NUM7 5
  uint8_t list7[] =  {0x82,0x00,0x00,0x80,0x00};
#define MAX_NUM8 5
  uint8_t list8[] =  {0x82,0x00,0x00,0x80,0x00};
#define MAX_NUM9 5
  uint8_t list9[] =  {0x82,0x00,0x00,0x80,0x00};
#define MAX_NUM10 2
  uint8_t list10[] =  {0x3A,0x3A};

  Serial.print(millis());
  Serial.print(",");
  for(int i=0;i<MAX_NUM1;i++){
    Serial.print(list1[i],HEX);
    Serial.print(",");
  }  
  Serial.print("\n");
  delay(1000);

  Serial.print(millis());
  Serial.print(",");
  for(int i=0;i<MAX_NUM2;i++){
    Serial.print(list2[i],HEX);
    Serial.print(",");
  }  
  Serial.print("\n");
  delay(1000);

  Serial.print(millis());
  Serial.print(",");
  for(int i=0;i<MAX_NUM3;i++){
    Serial.print(list3[i],HEX);
    Serial.print(",");
  }  
  Serial.print("\n");
  delay(1000);

  Serial.print(millis());
  Serial.print(",");
  for(int i=0;i<MAX_NUM4;i++){
    Serial.print(list4[i],HEX);
    Serial.print(",");
  }  
  Serial.print("\n");
  delay(1000);
  
  Serial.print(millis());
  Serial.print(",");
  for(int i=0;i<MAX_NUM5;i++){
    Serial.print(list5[i],HEX);
    Serial.print(",");
  }  
  Serial.print("\n");
  delay(1000);

  Serial.print(millis());
  Serial.print(",");
  for(int i=0;i<MAX_NUM6;i++){
    Serial.print(list6[i],HEX);
    Serial.print(",");
  }  
  Serial.print("\n");
  delay(1000);

  Serial.print(millis());
  Serial.print(",");
  for(int i=0;i<MAX_NUM7;i++){
    Serial.print(list7[i],HEX);
    Serial.print(",");
  }  
  Serial.print("\n");
  delay(1000);

  Serial.print(millis());
  Serial.print(",");
  for(int i=0;i<MAX_NUM8;i++){
    Serial.print(list8[i],HEX);
    Serial.print(",");
  }  
  Serial.print("\n");
  delay(1000);
 
  Serial.print(millis());
  Serial.print(",");
  for(int i=0;i<MAX_NUM9;i++){
    Serial.print(list9[i],HEX);
    Serial.print(",");
  }  
  Serial.print("\n");
  delay(1000);

  Serial.print(millis());
  Serial.print(",");
  for(int i=0;i<MAX_NUM10;i++){
    Serial.print(list10[i],HEX);
    Serial.print(",");
  }  
  Serial.print("\n");
  delay(1000);
}

上のサンプルコードを、M5ATOMで動かすと、以下の出力をシリアルに出力します。

出力結果

466095,82,0,0,80,0,
467095,82,0,0,80,0,
468095,82,0,0,80,0,
469095,3A,3A,
470095,1,88,12,CB,0,
471095,BA,BA,
472095,82,0,0,80,0,
473095,DA,DA,
474095,3A,3A,
475095,82,0,0,80,0,
476095,82,0,0,80,0,
477095,82,0,0,80,0,
478095,82,0,0,80,0,
479095,3A,3A,
480095,1,88,12,CB,0,
481095,BA,BA,
482095,82,0,0,80,0,
483095,DA,DA,
484095,3A,3A,
485095,82,0,0,80,0,
486095,82,0,0,80,0,
487095,82,0,0,80,0,
488095,82,0,0,80,0,
489095,3A,3A,
490095,1,88,12,CB,0,
491095,BA,BA,
492095,82,0,0,80,0,

PC側のプログラムの実行方法

動かし方

python3 app.py

実行結果

405095,82,0,0,80,0,
406095,82,0,0,80,0,
407095,82,0,0,80,0,
408095,82,0,0,80,0,
409095,3A,3A,
410095,1,88,12,CB,0,
411095,BA,BA,
412095,82,0,0,80,0,
413095,DA,DA,
414095,3A,3A,
415095,82,0,0,80,0,
416095,82,0,0,80,0,
417095,82,0,0,80,0,
418095,82,0,0,80,0,
420095,1,88,12,CB,0,

データベースに格納されたかの確認

次に、受信したシリアルデータがデータベースに書かれているかを確認します。

データベースに書かれた内容を確認する方法

PC側で、以下のソースを動かしてください。

import sqlite3

dbname = 'db_serial.sqlite'
conn = sqlite3.connect(dbname)
cur = conn.cursor()

# terminalで実行したSQL文と同じようにexecute()に書く
cur.execute('SELECT * FROM mytable')

# 中身を全て取得するfetchall()を使って、printする。
getdata = cur.fetchall()

for n in getdata:
    print(n)

cur.close()
conn.close()

実行結果

(1, 1606642174.0428805, 405095, '82', '405095,82,0,0,80,0,')
(2, 1606642175.0502684, 406095, '82', '406095,82,0,0,80,0,')
(3, 1606642176.0426283, 407095, '82', '407095,82,0,0,80,0,')
(4, 1606642177.0444062, 408095, '82', '408095,82,0,0,80,0,')
(5, 1606642178.03744, 409095, '3A', '409095,3A,3A,')
(6, 1606642179.050217, 410095, '1', '410095,1,88,12,CB,0,')
(7, 1606642180.0404322, 411095, 'BA', '411095,BA,BA,')
(8, 1606642181.0408137, 412095, '82', '412095,82,0,0,80,0,')
(9, 1606642182.041625, 413095, 'DA', '413095,DA,DA,')
(10, 1606642183.0495136, 414095, '3A', '414095,3A,3A,')
(11, 1606642184.041849, 415095, '82', '415095,82,0,0,80,0,')
(12, 1606642185.049531, 416095, '82', '416095,82,0,0,80,0,')
(13, 1606642186.0429475, 417095, '82', '417095,82,0,0,80,0,')
(14, 1606642187.043493, 418095, '82', '418095,82,0,0,80,0,')
(15, 1606642188.0337398, 419095, '3A', '419095,3A,3A,')
(16, 1606642189.0412445, 420095, '1', '420095,1,88,12,CB,0,')

受信したシリアルデータをデータベースに正しく書き込まれていることがわかります。

まとめ

IoTプログラミングの一環として、デバイスから取得したシリアルデータをデータベースに格納する方法を紹介しました。

コメント

タイトルとURLをコピーしました