仕事をさぼりやすいように人が来たら画面をコマンドプロンプトに切り替えてみる

やりたいこと

仕事さぼっているのがばれないように、人が近づいたらゲーム画面をコマンドプロンプト等(なんとなく黒くてそれっぽい画面)に切り替えられるようにする

必要要素

  • 人が近づいたことを検知する
  • コマンドプロンプト画面でゲーム画面を隠す

実装方針

人が近づいたことを検知する

何かのセンサーで人が近づいたことを検知すればOK。手持ちセンサーでそこそこの距離を測れる超音波距離センサー(HC-SR04)があったのでそいつを利用。角度は15度とほぼ正面しか測れないけどとりあえずこいつで。

コマンドプロンプト画面でゲーム画面を隠す

キーボード入力をマイコン(Raspberry Pi PICO)で自動化する。ライブラリを使ったら簡単にできるらしいできた。

実装技術

Circuit PythonだとAdafruitのライブラリで超音波距離センサーとキーボード入力もそろっていたのでCircuit Pythonを使った。

開発環境(エディタ?)

最初はVS Codeで開発しようとしたけどPICO開発用のPICO-goが新しいVSCodeだと使えないのでメジャーどころのThonnyにした。

なお、こちらにあるようにVSCodeのバージョンを1.65.2に落としたら動くはず。(いったんうごいていたけど油断していたらVSCodeのバージョンアップ走っていて使えなくなっていたので面倒になった。)

また、こちらにあるようにForkされたPico-goをビルドしてもよい模様。

実装

Circuit Pythonのインストール

公式からダウンロードしてインストール。(参考

コマンドプロンプト画面でゲーム画面を隠す

(ライブラリのインストール説明の都合でコマンドプロントから説明)

こちらを参考にHIDのライブラリをインストール。

Windowsでコマンドプロンプトを全画面起動するキー操作は以下。ついでになにかそれっぽい情報を出すためにDir結果も表示(実際に打つとわかりやすい)

  1. Windowsボタン(プログラムの検索画面を開く)
  2. “cmd”キー入力後 Enter (コマンドプロンプト起動)
  3. “dir” キー入力後Enter(Dir実行。ぱっとみそれっぽい情報を表示するため。)
  4. Alt押しながらEnter(コマンドプロンプト全画面か)

Windowsの反応時間を見なくてはいけないかもしれないのでちょいちょいスリープを入れているけど待ちが必要かはわからない。

なお、キーボードの種類指定できるけど日本語はなさげなので必要なら自分で書くか探さないといけない。

人が近づいたことを検知する

こちらからadafruit_hcsr04ライブラリをインストール。HIDの時と同じようにPICOのlibディレクトリにいれればよい。(adafruit_hcsr04.pyで最低限動くはず)

ハードとしてはPICOとhcsr04をジャンパーでつなぐ。

GP5とGP6はプログラムでGPIOピンなら任意指定に変更可能。ピンの役割はこちら

PICOHCSR04
VBUSvcc
GNDgnd
GP5trig
GP6echo

以下で値はとれる

import adafruit_hcsr04
sonar = adafruit_hcsr04.HCSR04(trigger_pin=board.GP5, echo_pin=board.GP6)
distance = sonar.distance

取り急ぎプログラムべたばり

何個もコマンドプロンプト立ち上げたり荒いけど使いながら調整する。プログラムもおもむろに書き直す。(HIDの試験用だったのでこのまま解体されるかもかも)

import microcontroller

import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS

from adafruit_hid.keycode import Keycode

import time
import board
import adafruit_hcsr04

keyboard = Keyboard(usb_hid.devices)
layout = KeyboardLayoutUS(keyboard)

sonar = adafruit_hcsr04.HCSR04(trigger_pin=board.GP5, echo_pin=board.GP6)
time.sleep(1)

while True:
    try:
        distance = sonar.distance
        if distance < 150:
            print('かくせ')
            
            keyboard.send(Keycode.WINDOWS)
            time.sleep(0.2)
            
            layout.write('cmd')
            time.sleep(0.1)
            keyboard.send(Keycode.ENTER)
            time.sleep(0.2)
            
            layout.write('dir\n')
            
            time.sleep(0.2)
            keyboard.send(Keycode.ALT,Keycode.ENTER)
            
        else:
            print("OK")
        
    except RuntimeError:
        print("Retrying!")
    time.sleep(2)

Pico-Goが新しいVS Codeだと動かない模様

暫定対処

取り急ぎVS Codeを動くバージョンの1.65.2にダウン。Windows64はこちら 他はこちらみてバージョンを1.65.2にて適宜。

(2022/05/30追記)

また、こちらにあるようにForkされたPico-goをビルドしてもよい模様。

起きていたエラー

VS Codeの拡張機能エラーに下のが出ていた。

 → c:\Users\kitam\.vscode\extensions\chriswood.pico-go-1.4.3\node_modules\@serialport\bindings\lib\binding\node-v101-win32-x64\bindings.node
	at bindings (c:\Users\kitam\.vscode\extensions\chriswood.pico-go-1.4.3\node_modules\bindings\bindings.js:126:9)
	at Object.<anonymous> (c:\Users\kitam\.vscode\extensions\chriswood.pico-go-1.4.3\node_modules\@serialport\bindings\lib\win32.js:1:98)
	at Module.u._compile (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:1313)
	at Object.Module._extensions..js (node:internal/modules/cjs/loader:1216:10)
	at Module.load (node:internal/modules/cjs/loader:1035:32)
	at Module._load (node:internal/modules/cjs/loader:876:12)
	at Function.c._load (node:electron/js2c/asar_bundle:5:13331)
	at Function.i._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:32156)
	at Function.E._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:28749)
	at Function.g._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:99:61429)
	at Module.require (node:internal/modules/cjs/loader:1059:19)
	at h (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:699)
	at Object.<anonymous> (c:\Users\kitam\.vscode\extensions\chriswood.pico-go-1.4.3\node_modules\@serialport\bindings\lib\index.js:6:22)
	at Module.u._compile (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:1313)
	at Object.Module._extensions..js (node:internal/modules/cjs/loader:1216:10)
	at Module.load (node:internal/modules/cjs/loader:1035:32)
	at Module._load (node:internal/modules/cjs/loader:876:12)
	at Function.c._load (node:electron/js2c/asar_bundle:5:13331)
	at Function.i._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:32156)
	at Function.E._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:28749)
	at Function.g._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:99:61429)
	at Module.require (node:internal/modules/cjs/loader:1059:19)
	at h (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:699)
	at Object.<anonymous> (c:\Users\kitam\.vscode\extensions\chriswood.pico-go-1.4.3\node_modules\serialport\lib\index.js:2:17)
	at Module.u._compile (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:1313)
	at Object.Module._extensions..js (node:internal/modules/cjs/loader:1216:10)
	at Module.load (node:internal/modules/cjs/loader:1035:32)
	at Module._load (node:internal/modules/cjs/loader:876:12)
	at Function.c._load (node:electron/js2c/asar_bundle:5:13331)
	at Function.i._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:32156)
	at Function.E._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:28749)
	at Function.g._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:99:61429)
	at Module.require (node:internal/modules/cjs/loader:1059:19)
	at h (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:699)
	at Object.<anonymous> (c:\Users\kitam\.vscode\extensions\chriswood.pico-go-1.4.3\lib\connections\pyserial.js:20:19)
	at Module.u._compile (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:1313)
	at Object.Module._extensions..js (node:internal/modules/cjs/loader:1216:10)
	at Module.load (node:internal/modules/cjs/loader:1035:32)
	at Module._load (node:internal/modules/cjs/loader:876:12)
	at Function.c._load (node:electron/js2c/asar_bundle:5:13331)
	at Function.i._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:32156)
	at Function.E._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:28749)
	at Function.g._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:99:61429)
	at Module.require (node:internal/modules/cjs/loader:1059:19)
	at h (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:699)
	at Object.<anonymous> (c:\Users\kitam\.vscode\extensions\chriswood.pico-go-1.4.3\lib\pymakr.js:18:17)
	at Module.u._compile (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:1313)
	at Object.Module._extensions..js (node:internal/modules/cjs/loader:1216:10)
	at Module.load (node:internal/modules/cjs/loader:1035:32)
	at Module._load (node:internal/modules/cjs/loader:876:12)
	at Function.c._load (node:electron/js2c/asar_bundle:5:13331)
	at Function.i._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:32156)
	at Function.E._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:28749)
	at Function.g._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:99:61429)
	at Module.require (node:internal/modules/cjs/loader:1059:19)
	at h (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:699)
	at Object.<anonymous> (c:\Users\kitam\.vscode\extensions\chriswood.pico-go-1.4.3\lib\activator.js:28:15)
	at Module.u._compile (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:1313)
	at Object.Module._extensions..js (node:internal/modules/cjs/loader:1216:10)
	at Module.load (node:internal/modules/cjs/loader:1035:32)
	at Module._load (node:internal/modules/cjs/loader:876:12)
	at Function.c._load (node:electron/js2c/asar_bundle:5:13331)
	at Function.i._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:32156)
	at Function.E._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:28749)
	at Function.g._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:99:61429)
	at Module.require (node:internal/modules/cjs/loader:1059:19)
	at h (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:699)
	at Object.<anonymous> (c:\Users\kitam\.vscode\extensions\chriswood.pico-go-1.4.3\pymakr.js:1:81)
	at Module.u._compile (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:4:1313)
	at Object.Module._extensions..js (node:internal/modules/cjs/loader:1216:10)
	at Module.load (node:internal/modules/cjs/loader:1035:32)
	at Module._load (node:internal/modules/cjs/loader:876:12)
	at Function.c._load (node:electron/js2c/asar_bundle:5:13331)
	at Function.i._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:32156)
	at Function.E._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:28749)
	at Function.g._load (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:99:61429)
	at Module.require (node:internal/modules/cjs/loader:1059:19)
	at require (node:internal/modules/cjs/helpers:102:18)
	at Function.r [as __$__nodeRequire] (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\loader.js:5:101)
	at u._loadCommonJSModule (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:104:30318)
	at u._doActivateExtension (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:90:13361)
	at u._activateExtension (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:90:12313)
	at processTicksAndRejections (node:internal/process/task_queues:96:5)
	at async g._activate (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:85:8154)
	at async g._waitForDepsThenActivate (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:85:8096)
	at async g._initialize (c:\Users\kitam\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:85:7460)

isuueとか見るとVS Codeが1.66になったときにNodeのバージョンも変わって不整合でテイルっぽい。

Aliで買ったToF距離センサ(Vl53l0x)の動作確認

結果、動いた。ものはこちらで買った。

確認環境

Arduino UNO

多分ほかでも大丈夫。

Adafruit_VL53L0X

Arduino IDEのライブラリを管理からVL53L0Xで検索したらでてきたライブラリ。

vl53l0x.ino

ライブラリ に入っていたサンプルスケッチ

配線

ArduinoVL53L0X
3.3VVIN
GNDGND
SCLSCL
SDASDA
未接続xshutdown (reset)
未接続gpio (interrupt)

何作ろう。

MHZ19ターミナルタイプのコネクター

MHZ19をはじめとするMHZ14やその他Winsen社製のターミナルタイプですがコネクターがかなり固いです。

また、19はコネクターのメスとセンサー本体の間が折り取れるようになっているのでコネクター部分をしっかり押さえて差し込まないと折れてしまうことがあります。

向きは以下の写真の通りです。

Aliで買った1.3インチのOLEDの動作確認

alieで買ったOLEDの動作確認のメモ。

買ったのもはこちら。商品のレビューが星一個だったけどストアの全般的な評価は悪くない。

秋月で売っているこれの一回り大きいものだと思う。(持っていないので多分)

かったとこにデータ乗っていないけどたぶん同じ物あつかっているとこ(こことか)みると3v-5vでSH1106ドライバで動くとのこと。

接続はしたな感じ

LED-Arduinoで

  • VDD-5V(または3.3VでもOK)
  • GND-GND
  • SCK-SCL
  • SDA-SDA

ライブラリはこいつを使ってExampleのsh1106_128x64_i2c.inoで動作。

既存のCO2センサー(EPEA-CO2-NDIR-04)の画面を変えたバージョンを作りつつちょっと触ってみる。(といってもtextでればよいのでさらっと)

M5Stack+MHZ19B/Cキット組み立て方法

わかりにくい場合、画像等を追加します。購入モールのメッセージ、twitter等でご連絡ください。(本ブログは数週間に1度程度しかチェックしていません)

半田付け

半田付けは「MHZ19用基板にMHZ19及びピンヘッダーを付けつ手順」と「LEDと抵抗をつける手順」の2ステップです。

MHZ19用基板

ピンヘッダーを10+5個分基盤につけます。上面側にピンも来るようにつけてください。水平が狂うとM5Stackに差し込んだ時の接触が悪くなります。(ある程度は付属のワッシャ等で調整可能)

LED

抵抗をLEDの足につけます。アノード/カソード好みで大丈夫です。長さはケースにおさまる程度に修正してください。付け終わったらビニテ等でそれぞれ接触しないように絶縁してください。

LEDはAliexpresで購入したこれを使っています。

組み立て

M5Stack

底面(アクリルの板)、ナット、M5StackのM3ボルト取り付け穴の順になるように取り付けます。ボルト/底面/ナットを手で大体しめた後にM5Stackの背面取りつけ穴に合わせてドライバーでしめるとやりやすいです。

MHZ19

ワッシャ、底面(アクリルの板)、ナット(及び必要であれば高さ調整ワッシャ)、基板、ナットの順に取り付けます。使用するのは短めのプラスチックボルトです。

ナットを少しゆるめてピンヘッダーをスライドさせてM5Stackに差し込みます。差し込んだ後に改めて締め直してください。

LED

M5Stack上面の22番にアノード、Gにカソードを差し込みます。

ケースカバー

それぞれ上からはめてボルトとナットで固定します。

M5Stack+MHZ19Bで通信機能詰め込みCO2センサー

キットの組み立て方はこちらから(MHZ19Cも同一手順)

M5StackとCO2センサーモジュールMHZ19Bを使って通信機能を詰め込んだCO2センサーを作成した。一応1000ppm警告のLEDも付いている。使える通信(と表示)は以下。

  • もとから付いている画面
  • シリアルでのPC等へのUSB経由出力
  • Wifi経由の出力(サーバになる、2.4G回線のみ)
  • bluetooth出力

画面とシリアル出力は常に起動。Wifiとbluetoothは起動時に選択した場合のみ。

画面はこんな感じ。

シリアル出力はこんな感じ。teraterm等で確認するのが楽かも。転送速度は9600。Windows用のCO2閲覧ソフトでも(これに限らずJSONできたら)みられる用にする予定。

[yoshitake@localhost ~]$ stty -F /dev/ttyUSB0 raw 9600
[yoshitake@localhost ~]$ sudo  cat /dev/ttyUSB0
{"CO2":402}
{"CO2":401}

WifiはM5Stack起動時にAボタン(画面向かって左側)が押されていたら起動。繋がった際に画面にipアドレスが出力されるのでそのアドレスにアクセスするとJSONが返ってくる。192.168.1.15がM5StackのIPだとするとhttp://192.168.1.15/で値がJSONで返却される。呼び出し元のページがあるとIoTなこといろいろできる。なお、Wifiに10秒以上つながらなかったら設定モードに入る。設定はスマホアプリのESPTouchというものを使用。英語だけれどもパスワード入れさえすれば動く。注意点はスマホのWIFIが2.4Gのアクセスポイントに繋がっていないといけない。

bluetoothは起動時にBボタン(画面真ん中)が押されていたら起動。CO2Sensorという名前のデバイスが現れるのでそちらに接続すると数値のみが定期的(いまは6秒)で送られる。AndroidであればSerial Bluetooth Terminalというもので取り敢えず値がとれる。

なお、起動後にAボタンとCボタン(画面向かって右側)を長押しするとキャリブレーション(今の濃度を400とみなして基準値のリセット)を実行する。「日光の当たらない場所(できれば夜間)」で「20分以上きれいな外気」にあててから実行する。補正する為の比較対照が無い状態でも通常±50ppm以内には収まる。

ソースはこちら

ハードはM5StackBasicとこちらのキット

Raspberry Pi Pico + SSD1306 + CircuitPython

表題の組み合わせでハマったのでメモ

環境

  • Raspberry Pi Pico
  • CircuitPython(adafruit-circuitpython-raspberry_pi_pico-en_GB-6.2.0.uf2)
  • SSD1306ドライバーのOLED(128*32)
  • ライブラリ(adafruit-circuitpython-bundle-6.x-mpy-20210430)

動いたライブラリ

adafruit_displayio_ssd1306.mpy他(adafruit_scd_30.mpyはセンサーのライブラリで不要)

~/develop/scd30_pico/lib$ ls
adafruit_bus_device    adafruit_displayio_ssd1306.mpy  adafruit_scd30.mpy
adafruit_display_text  adafruit_framebuf.mpy

コード。

# SPDX-FileCopyrightText: 2020 by Bryan Siepert, written for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
import time
import board
import busio
import displayio
import terminalio
from adafruit_display_text import label
import adafruit_displayio_ssd1306

import adafruit_scd30

displayio.release_displays()

i2c_oled = busio.I2C(scl=board.GP19, sda=board.GP18)
display_bus = displayio.I2CDisplay(i2c_oled, device_address=0x3C)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)

scd = adafruit_scd30.SCD30(i2c_oled)

try:
    while True:
        CO2 = scd.CO2
        print(CO2)
        text_group = displayio.Group(max_size=10)

        # Draw a label
        text = str(CO2)
        text_area = label.Label(terminalio.FONT, text=text, color=0xFFFFFF, x=0, y=4)
        text_group.append(text_area)
        display.show(text_group)

        time.sleep(2)
except Exception as e:
    print(type(e))
    print(e.args)
    print(e)

動かなかったライブラリ

adafruit_ssd1306

事象

初期化すると、PCにUSBとして認識されなくなる

i2c = busio.I2C(board.GP21, board.GP20)
display = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)

上記で下の感じ

[4936305.202012] usb 2-2: new full-speed USB device number 74 using xhci_hcd
[4936305.202193] usb 2-2: Device not responding to setup address.
[4936305.410209] usb 2-2: Device not responding to setup address.
[4936305.618018] usb 2-2: device not accepting address 74, error -71
[4936305.746021] usb 2-2: new full-speed USB device number 75 using xhci_hcd
[4936305.746221] usb 2-2: Device not responding to setup address.
[4936305.954217] usb 2-2: Device not responding to setup address.
[4936306.162031] usb 2-2: device not accepting address 75, error -71
[4936306.162095] usb usb2-port2: unable to enumerate USB device

バグなのか使い方か不明。まだissueの流れが早すぎて見るの諦めた。

CO2センサーMHZ19CとPCをUSB(シリアル変換)で接続

MHZ19CとPCをUSBで接続する。多分最小構成。

少しだけしゅっとさせたハード stores(少し安め) / amazon

widdows10向けアプリ

Windows向けの閲覧アプリ EPEA-CO2-NDIR-05(USB接続CO2センサー)を指してこちらをインストールすれば使えます。(ドライバーが無い場合はこちらのドライバーも必要です。分からない場合は両方入れておけば間違いはないです。)

v0.3.0

2021/04/18公開 ダウンロード先

CSVダウンロード機能追加

新しいもの13万件分(連続稼働させている場合約1週間分)のデータをCSVとしてダウンロードします。

暖機中の500やエラー、起動待ちの-1/-9もダウンロードされます。

日時のデータにはミリ秒まで入っています。エクセルの標準だと細かいデータまでは表示されませんが必要性に応じて適宜、書式を設定してください。

v0.2.0

2021/04/17公開 ダウンロード先

このバージョンで使用されているライブラリ(※)に環境依存のものが含まれています。おおよその環境で動くものを選択したつもりですがこのバージョンにあげたら動かなくなった場合はライブラリの可能性が高いです。このバージョンから動作しない場合はご連絡ください。

※ C:\Program Files (x86)\Epea\CO2Viewer\SQLite.Interop.dll です。これで伝わる人は適宜入れ替えてください。

手動キャリブレーション機能追加

現在の濃度を400ppm(おおよそ外気平均)として補正する機能です。USBを刺したまま換気をし綺麗な外気に20分以上さらした状態で実行してください。

ログ出力追加

C:\Users\ユーザ名\AppData\Roaming\epea\co2viewer にall.logが出力されるようになりました。設定はC:\Program Files (x86)\Epea\CO2Viewer\CO2View.exe.config 内にあります。

DB出力追加

C:\Users\ユーザ名\AppData\Roaming\epea\co2viewer\co2viewerdb.sqlite に出力されるようになりました。出力機能はこれから作りますがとり急ぎDB Browser(SQlite)等で閲覧可能です。

v0.0.3

2021/04/15公開 ダウンロード先

閲覧機能

CO2センサーから読み取った値を画面上に表示します。USBを刺したポートを選んで接続を押すと値を読み込みます。なお、誤差が100ppm程度ある目安で使用してください。(それでも1万円未満で市販されているCO2センサーの中ではおそらく最高精度です。)

0は初期状態、-1は読み込み準備中、-9はエラー、その他値はセンサーが返した値です。

USBを刺してから2分ほど暖機にかかるのでその後から正確になります。

数値800未満は背景が緑、800以上1000未満は背景が黄色、1000以上は赤になります。自治体等の基準がまだ不明瞭ですがおおよその目安にしてください。

自動キャリブレーションON/OFF機能

基準値補正を自動で行うか否かを選択する機能です。24時間以内に観測された最低値を外気基準値として補正する機能です。自動キャリブレーションをONにしていると換気ができていない場合や、電圧が不安定な場合等に値が不正確になることが多いのでOFFにした利用を推奨しております。(選べるようにしておいて欲しいという声がありましたので機能を付けています。。。)

Windowsアプリの話が長くなってきましたがやっとここからMHZ19CとPCをUSBで接続する。多分最小構成の話再開。

必要なもの

USBシリアル変換モジュール

USBとシリアルを変換するやつ。MHZ19Cで200mAぐらい必要なのでPCから給電されたものがそのままピンに出てくるタイプでないといけない。CH380GというICのものなら大体ドライバーがPCに入っていると思うけどなければ自分でインストール。

参照 動作確認できたもの Amazonの購入元KKHMF 3個 CH340モジュール STC マイクロ コントローラー ダウンロード USBターンTTLシリアル

MHZ19C

定番のCO2センサーモジュール。

データシート

2021/03時点送料込み国内最安値

秋月電子(送料抜きだと最安値。他のものも一緒に買う人はこっちが安い)

しゅっとさせたやつ(EPEA-CO2-NDIR-05)

stores amazon 手数料の関係でstoresの方が安い。

PC

USBがあるもの。電源が弱いやつだと不安定になると思う。試しているOSはCentOS7

接続方法

以下のように接続(前がモジュール後ろがMHZ19)

  • 5V-VIN
  • GND-GND
  • TXD-Rx
  • RXD-Tx

プログラム

軽く探したところ使いやすそうなライブラリはまだ見つからなかった。ラズパイ想定のライブラリから抜粋して動作確認。python3.7.1でpySerialいれてある。/dev/ttyUSB0は環境によって(都度)変わるので適宜読みかえ

[yoshitake@localhost usbpy]$ pyenv version
3.7.1 (set by /home/yoshitake/develop/usbpy/.python-version)

pip install pyserial
import serial
import traceback
import time

serial_dev = '/dev/ttyUSB0'


def connect_serial():
    return serial.Serial(serial_dev,
                         baudrate=9600)


def mh_z19():
    try:
        ser = connect_serial()
        result = ser.write(b"\xff\x01\x86\x00\x00\x00\x00\x00\x79")
        s = ser.read(9)
        return {'co2': s[2]*256 + s[3]}
    except:
        traceback.print_exc()
    finally:
        ser.close()


def main():

    while 1:
        value = mh_z19()
        co2 = value["co2"]
        print('CO2:', co2)
        time.sleep(5)


if __name__ == '__main__':
    main()

出力はしたみたいな感じで、暖機が終わるまで少しかかるはず。(ただ、MHZのメーカーはちょいちょい動きをかえてくるのでだいたいの目安。)

yoshitake@localhost usbpy]$ python test2.py 
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 500
CO2: 465
CO2: 451

アンドロイドの野良アプリ。動作確認レベルの出来だけど値は取得できる。自分でインストールできる人向け。 こちら

ラズパイでMHZ19Bが動作しない時のエラーパラーン(切り分け用)

UARTが有効になっていない。

pi@raspberrypi:~ $ sudo cat /boot/config.txt |grep uart
enable_uart=0
pi@raspberrypi:~ $ sudo python3 -m mh_z19
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/serial/serialposix.py", line 265, in open
    self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
FileNotFoundError: [Errno 2] No such file or directory: '/dev/ttyAMA0'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/mh_z19/__init__.py", line 62, in mh_z19
    ser = connect_serial()
  File "/usr/local/lib/python3.7/dist-packages/mh_z19/__init__.py", line 58, in connect_serial
    timeout=1.0)
  File "/usr/local/lib/python3.7/dist-packages/serial/serialutil.py", line 240, in __init__
    self.open()
  File "/usr/local/lib/python3.7/dist-packages/serial/serialposix.py", line 268, in open
    raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
serial.serialutil.SerialException: [Errno 2] could not open port /dev/ttyAMA0: [Errno 2] No such file or directory: '/dev/ttyAMA0'
A dependency job for serial-getty@ttyAMA0.service failed. See 'journalctl -xe' for details.
null