Skip to content

Instantly share code, notes, and snippets.

@gnue
Last active December 19, 2015 16:19
Show Gist options
  • Save gnue/5983381 to your computer and use it in GitHub Desktop.
Save gnue/5983381 to your computer and use it in GitHub Desktop.
富士通BSC F-PLUG から温度・湿度・照度・消費電力を取出すための実証コード
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'rubygems'
require 'serialport'
class Fplug
DEFAULT_PORT = '/dev/tty.fplug'
REQ_TEMPLATE = [0x10, 0x81, 0x00, 0x00, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x62, 0x01, 0x00, 0x00]
INFO_TYPES = {
temp: {classcode: 0x11, epc1: 0xe0, unit: '℃', scale: 0.1}, # 温度
humid: {classcode: 0x12, epc1: 0xe0, unit: '%', scale: 1}, # 湿度
illum: {classcode: 0x0D, epc1: 0xe0, unit: 'lx', scale: 1}, # 照度
rwatt: {classcode: 0x22, epc1: 0xe2, unit: 'W', scale: 0.1}, # 消費電力
}
class << INFO_TYPES
INDEXES = {}
def make_index(key)
index = {}
self.each_value { |type| index[type[key]] = type }
index
end
def find_by_key(value, key)
INDEXES[key] ||= make_index(key)
INDEXES[key][value]
end
end
def self.open(port = nil)
fplug = new(port)
yield fplug
rescue
ensure
fplug.close
end
def initialize(port = nil)
port ||= DEFAULT_PORT
@sp = SerialPort.new(port, 9600, 8, 1, SerialPort::NONE) # 9600bps, 8bit, ストップビット1, パリティ無し
@tid = 0
end
def close
@sp.close
end
def responce_clear
begin
@sp.read_nonblock(256)
rescue
end
end
def send(kind)
type = INFO_TYPES[kind.downcase]
req = REQ_TEMPLATE.dup
req[8], req[12] = type[:classcode], type[:epc1]
@req = req.pack('C*')
@req[2..3] = [@tid += 1].pack('v') # TID(トランザクションID)
@sp.write @req
end
# データを符号付整数で取出す(実機のエンディアンに非依存)
def signed_int(data, bytes)
case bytes
when 1
format = 'c'
when 2
format = 'v'
signed = 's'
when 4
format = 'V'
signed = 'i'
end
return unless format
a = data.unpack(format)
a = a.pack(signed.upcase).unpack(signed) if signed
a.first
end
def receive
buf = @sp.read(1) + @sp.read_nonblock(255)
r = buf[0..13].unpack('C*')
seoj1, seoj2 = r[4..5]
esv, opc, epc1, pdc1 = r[10..13]
return unless esv == 0x72 && 0 < pdc1
value = signed_int(buf[14, pdc1], pdc1)
type = INFO_TYPES.find_by_key(seoj2, :classcode)
return [nil, nil] unless type
[value * type[:scale], type[:unit]]
end
def read(types = [:temp, :humid, :illum, :rwatt])
data = {}
types.each { |kind|
responce_clear
send kind
value, unit = receive
data[kind] = value
}
data
end
end
if $0 == __FILE__
port = ARGV.shift
def num_to_s(v)
v.kind_of?(Float) ? sprintf("%.1f", v) : v.to_s
end
def ltsv(data)
data.map { |k, v| "#{k}:#{num_to_s v}" }.join("\t")
end
def tsv(data)
data.map { |k, v| num_to_s(v) }.join("\t")
end
def format(data)
data.each { |key, value|
type = Fplug::INFO_TYPES[key]
next unless type
printf("%6s: %7.1f%s\n", key, value, type[:unit])
}
end
Fplug.open(port) { |fplug|
data = {time: Time.now}
data.merge! fplug.read
# わかりやすく表示
#format(data)
# LTSV出力
#puts ltsv(data)
# TSV出力
puts tsv(data)
}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment