Skip to content

Instantly share code, notes, and snippets.

@tako2
Last active June 4, 2016 08:55
Show Gist options
  • Save tako2/966c4d778c6db8dabc7c to your computer and use it in GitHub Desktop.
Save tako2/966c4d778c6db8dabc7c to your computer and use it in GitHub Desktop.
Log serial text from ToCoStick (TWE - wireless usb device). This code needs python-serial and python-daemon.
#!/usr/bin/env python
# coding: UTF-8
from __future__ import with_statement
import sys
import serial
import os.path
import datetime
from optparse import OptionParser
from daemon import DaemonContext
from daemon.pidlockfile import PIDLockFile
#==============================================================================
# :788115017581000038002899000C04230000FFFFFFFFFFD4
# ^1^2^3^4^5^^^^^^^6^7^^^8^9^^^a^b^c^de1e2e3e4ef^g
#
# データフォーマット
# 1: 送信元の論理デバイスID (0x78 は子機からの通知)
# 2: コマンド(0x81: IO状態の通知)
# 3: パケット識別子 (アプリケーションIDより生成される)
# 4: プロトコルバージョン (0x01 固定)
# 5: LQI値、電波強度に応じた値で 0xFF が最大、0x00 が最小
# 6: 送信元の個体識別番号
# 7: 宛先の論理デバイスID
# 8: タイムスタンプ (秒64カウント)
# 9: 中継フラグ(中継済みなら1)
# a: 電源電圧[mV]
# b: 未使用
# c: DI の状態ビット。DI1(0x1) DI2(0x2) DI3(0x4) DI4(0x8)。1がOn(Lowレベル)。
# d: DI の変更状態ビット。DI1(0x1) DI2(0x2) DI3(0x4) DI4(0x8)。1が変更対象。
# e1~e4: AD1~AD4の変換値。0~2000[mV]のAD値を16で割った値を格納。
# ef: AD1~AD4の補正値 (LSBから順に2ビットずつ補正値、LSB側が AD1, MSB側が AD4)
# g: チェックサム
#==============================================================================
def parse_twe_message(res):
data = {}
data['dev_id'] = res[1:3]
data['cmd'] = res[3:5]
data['pkt_id'] = res[5:7]
data['protocol'] = res[7:9]
data['lqi'] = res[9:11]
data['from'] = res[11:19]
data['to_id'] = res[19:21]
data['timestamp'] = int(res[21:25], 16)
data['relay'] = res[25:27]
data['vol'] = int(res[27:31], 16)
data['di_st'] = res[33:35]
data['di_ch'] = res[35:37]
e1 = int(res[37:39], 16)
e2 = int(res[39:41], 16)
e3 = int(res[41:43], 16)
e4 = int(res[43:45], 16)
ef = int(res[45:47], 16)
data['ad1'] = ((e1 * 4) + (ef & 0x03)) * 4
ef = ef / 4
data['ad2'] = ((e2 * 4) + (ef & 0x03)) * 4
ef = ef / 4
data['ad3'] = ((e3 * 4) + (ef & 0x03)) * 4
ef = ef / 4
data['ad4'] = ((e4 * 4) + (ef & 0x03)) * 4
# chksum = ers[47:49]
return data
#==============================================================================
# Log TWE Message
#==============================================================================
log_items = ['dev_id', 'cmd', 'pkt_id', 'protocol', 'lqi', 'from', 'to_id',
'timestamp', 'relay', 'vol', 'di_st', 'di_ch',
'ad1', 'ad2', 'ad3', 'ad4'];
def log_twe(devfile, path):
twelog = None
templog = None
try:
ser = serial.Serial(devfile, 115200, timeout=1)
twelog = open(path + 'twelog.csv', 'a')
templog = open(path + 'templog.csv', 'a')
temp_val = 0
temp_cnt = 0
temp_min = -1
while True:
res = ser.readline()
if res.startswith(':'):
# print res
# Log All Data
now = datetime.datetime.today()
log = now.strftime('%Y%m%d,%H%M%S')
data = parse_twe_message(res)
# print data
for key in log_items:
if isinstance(data[key], int):
log += ',' + key + ':' + str(data[key])
else:
log += ',' + key + ':' + data[key]
log += '\n'
twelog.write(log)
twelog.flush()
# Log Temperature
cur_temp = (data['ad1'] - 424) / 6.25
if temp_min < 0 or temp_min == now.minute:
#print '+ ' + str(cur_temp)
temp_val += cur_temp
temp_cnt += 1
else:
#print str(temp_val) + ' / ' + str(temp_cnt),
temp_val /= temp_cnt
temp_val = round(temp_val, 2)
#print '= ' + str(temp_val)
log = now.strftime('%Y%m%d,%H%M') + ',' + str(temp_val)
log += '\n'
templog.write(log)
templog.flush()
#print ' ' + str(cur_temp)
temp_val = cur_temp
temp_cnt = 1
temp_min = now.minute
finally:
if twelog is not None:
twelog.close()
if templog is not None:
templog.close()
ser.close()
###############################################################################
if __name__ == '__main__':
parser = OptionParser()
parser.add_option("-p", "--path", dest="path",
help="PATH to write log at", metavar="PATH")
parser.add_option("-d", "--daemon",
action="store_true", dest="daemon", default=False,
help="daemonize")
(options, args) = parser.parse_args()
if len(args) == 0:
devfile = '/dev/ttyUSB0'
else:
devfile = args[0]
if options.path is None:
path = os.path.abspath(os.path.dirname(__file__)) + '/'
else:
path = options.path
if not path.endswith('/'):
path += '/'
if options.daemon:
dc = DaemonContext(pidfile=PIDLockFile('/tmp/twelog.pid'),
stderr = open('/tmp/twelog.err', 'w+'))
with dc:
log_twe(devfile, path)
else:
log_twe(devfile, path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment