Androud N がリリースされたようですが、ZenFone 2 には Android M が一向にきません。こないんでしょうか。
✖
|
Androud N がリリースされたようですが、ZenFone 2 には Android M が一向にきません。こないんでしょうか。
自宅のネットワーク、ちょいちょい特定のDNSがひけなくなるけど、なんなんだろうなあ。プロバイダのキャッシュサーバーがおかしいのだろうか……
『この美術には問題がある!』と『NEW GAME』が安心してみれて無限に可愛い女の子が喋る感じなのが良い
とりあえずメモだけ
Eagle の場合は pcb-gcode を使えばよかったが、これは Eagle の ULP で書かれているので KiCAD には使えない。pcb2gcode はガーバーファイルから直接 gcode に変換するのでどちらでも使える。
以下のパッチのブランチで実行
https://github.com/pcb2gcode/pcb2gcode/pull/47
millproject
# Use standard mm metric=true metricoutput=1 # front= back=Main-B.Cu.gbr outline=Main-Edge.Cuts.gbr drill=Main.drl back-output=back.gcode outline-output=outline.gcode drill-output=drill.gcode # https://github.com/chrysn-pull-requests/pcb2gcode/blob/graphical-documentation/man/options.svg zwork=-0.1 zsafe=1 mill-feed=500 mill-speed=10000 mill-vertfeed=200 offset=0.07679491924311227 #offset=10 extra-passes=1 zdrill=0.9 zchange=20 drill-feed=100 drill-speed=10000 milldrill=true # milldrill のときの直径 パッチが必要 milldrill-diameter=0.8 # for grbl nog81=true # 外形カット時のミル直径 cutter-diameter=1 zcut=-1 cut-feed=500 cut-speed=10000 cut-infeed=1 cut-side=back optimise=true zero-start=true dpi=1000
offset には削るエンドミルの半径を入れる。たとえば 30° 0.1mm のVカッターを -0.1mm で掘る (zwork=-0.1) にする場合 φ0.153mm なので、offset=0.0767 にする。
各 gcode を --zero-start で別々に生成すると原点がずれる。しかも --cutter-diameter を変えると外形レイヤーの基準がかわってしまう。
milldrill の場合 drill 系のオプションは無意味で、全て cutter 系のオプションが適用される。
milldrill のときの mill の直径は cutter-diameter と共用のようで、外形カットと穴開けで別の直径のエンドミルにできない…
KiCAD の時点で外形を大きくしておくか、パッチ書くしかない。→ 書いた
pcb2gcode は isolate な部分を全て削る設定にすることができない(と思う)。なので孤立した銅箔が生成されてしまう。 extra-passes=100 とかにすればできるだけ全て削れるっぽい。
offset を大きく設定すると voronoi アルゴリズムが有効になり、孤立した部分をなくせる (孤立した部分は近くの配線に吸収される)。配線というよりは銅箔面の領域分割という感じになる。PCB っぽくはないけどおもしろい。
まだこれは試してない。
http://www.apache.org/dist/httpcomponents/httpcore/RELEASE_NOTES-4.4.x.txt
httpcore-4.4.5 (2016-06-08) では 4.4.4 ではあったアノテーションが削られています。
Please note the following annotations originally based on CC-BY licensed source have been removed in this release: org.apache.http.annotation.GuardedBy org.apache.http.annotation.Immutable org.apache.http.annotation.NotThreadSafe org.apache.http.annotation.ThreadSafe
httpclient 4.5.1 や 4.5.2 はこれらのアノテーションを使ってるので、うっかり 4.4.5 が入ると死ぬようです。
以下のようにバージョン指定しました。
compile('org.apache.httpcomponents:httpcore:4.4.4')
compile('org.apache.httpcomponents:httpclient:4.5.2') 1時間ぐらいハマった。Java は辛い。
スマートメータのBルートサービスで Wi-SUN モジュールを使って瞬間消費電力を読み出す | tech - 氾濫原 にひき続き Wi-SUN モジュール ROHM BP35A1 と ECHONET Lite プロトコルを使い、スマートメータから値を取得するサンプルです。
前回のコードはさすがにちゃんと動かなすぎるものなので、多少まともにしたものを書きました。一応16時間ぐらい動かしても止まることなく動く感じです。
連続して動かす場合大事なところ
途中に環境変数で分岐していますが、片方はテスト用のコードです。Wi-SUN のスキャンが結構時間がかかってイライラするので、想定問答をシミュレーションしています。ちゃんとテスト化したほうがいいんですが、長時間実際に動かしてみるほうが有益だと思ったので限られた時間でそこまでやってません。
#!/usr/bin/env ruby -v
require 'stringio'
module ECHONET_Lite
EHD1 = 0b00010000
EHD2_DEFINED = 0x81
EHD2_ANY = 0x82
class ParseError < Exception
end
def self.parse_frame(frame)
ret = Frame.parse(frame)
unless ret.valid?
raise ParseError.new("not an ECHONET Lite frame")
end
ret
end
Frame = Struct.new(:ehd1, :ehd2, :tid, :edata) do
def self.parse(frame)
ret = self.new(*frame.unpack("CCna*"))
if ret.valid? && ret.format_defined?
ret.edata = EDATA.parse(ret.edata)
end
ret
end
def valid?
ehd1 == EHD1
end
def format_defined?
ehd2 == EHD2_DEFINED
end
def format_any?
ehd2 == EHD2_ANY
end
def pack
[ehd1, ehd2, tid].pack("CCn") + edata.pack
end
end
EDATA = Struct.new(:seoj, :deoj, :esv, :opc, :properties) do
def self.parse(edata)
ret = self.new(*edata.unpack("a3a3CCa*"))
ret.seoj = EOJ.parse(ret.seoj)
ret.deoj = EOJ.parse(ret.deoj)
props = []
StringIO.open(ret.properties) do |io|
ret.opc.times do
epc, pdc = *io.read(2).unpack("CC")
edt = io.read(pdc)
props << Property.new(epc, pdc, edt)
end
end
ret.properties = props
ret
end
def pack
seoj.pack + deoj.pack + [esv, opc].pack("CC") + properties.map {|i|
i.pack
}.join
end
end
EOJ = Struct.new(:class_group_code, :class_code, :instance_code) do
def self.parse(eoj)
self.new(*eoj.unpack("CCC"))
end
def pack
to_a.pack("CCC")
end
end
Property = Struct.new(:epc, :pdc, :edt) do
def pack
self.pdc = edt.length
[epc, pdc].pack("CC") + edt
end
end
end
require 'thread'
class SKSTACK_IP
EVENT_RECV_NS = 1
EVENT_RECV_NA = 2
EVENT_RECV_ECHO = 5
EVENT_COMPLETED_ED_SCAN = 0x1F
EVENT_RECV_BEACON = 0x20
EVENT_UDP_SENT = 0x21
EVENT_COMPLETED_ACTIVE_SCAN = 0x22
EVENT_PANA_ERROR = 0x24
EVENT_PANA_COMPLETED = 0x25
EVENT_RECV_SESSION_CLOSE = 0x26
EVENT_PANA_CLOSED = 0x27
EVENT_PANA_TIMEOUT = 0x28
EVENT_SESSION_EXPIRED = 0x29
EVENT_SEND_LIMIT = 0x32
EVENT_SEND_UNLOCK = 0x33
def initialize(port)
@event_callbacks = {}
@port = port
@port.set_encoding(Encoding::BINARY)
@rest = nil
@queue = Queue.new
@read_thread = Thread.start do
Thread.current.abort_on_exception = true
buffer = ""
while true
# need to know command name preceded by whole line
# because there is ERXUDP/ERXTCP which include length and any binary bytes.
c = @port.getc
if c.nil?
raise "unexpected IO closed"
end
buffer << c
case c
when ' ', "\r"
command = buffer.sub(/[\r ]$/, '')
case command
when "ERXUDP"
event = {}
event[:sender] = @port.gets(" ").sub(/\s+$/, '')
event[:dest] = @port.gets(" ").sub(/\s+$/, '')
event[:rport] = @port.gets(" ").sub(/\s+$/, '').unpack("n")[0]
event[:lport] = @port.gets(" ").sub(/\s+$/, '').unpack("n")[0]
event[:senderlla] = @port.gets(" ").sub(/\s+$/, '')
event[:secured] = @port.gets(" ").sub(/\s+$/, '')
datalen = @port.gets(" ").sub(/\s+$/, '')
event[:data] = @port.read(datalen.to_i(16))
@port.read(2) # ignore crlf
callback_event(:ERXUDP, event)
buffer.clear
when "ERXTCP"
event = {}
event[:sender] = @port.gets(" ").sub(/\s+$/, '')
event[:rport] = @port.gets(" ").sub(/\s+$/, '')
event[:lport] = @port.gets(" ").sub(/\s+$/, '')
datalen = @port.gets(" ").sub(/\s+$/, '')
event[:data] = @port.read(datalen.to_i(16))
@port.read(2) # ignore crlf
callback_event(:ERXTCP, event)
buffer.clear
when "EPONG"
event = {}
event[:sender] = @port.gets("\n").sub(/\s+$/, '')
callback_event(:EPONG, event)
buffer.clear
when "ETCP"
event = {}
event[:status] = @port.gets(" ").sub(/\s+$/, '')
if event[:status] == "1"
event[:handle] = @port.gets(" ").sub(/\s+$/, '')
event[:ipaddr] = @port.gets(" ").sub(/\s+$/, '')
event[:rport] = @port.gets(" ").sub(/\s+$/, '')
event[:lport] = @port.gets("\n").sub(/\s+$/, '')
else
event[:handle] = @port.gets("\n").sub(/\s+$/, '')
end
callback_event(:EPONG, event)
buffer.clear
when "EADDR", "ENEIGHBOR"
# ignore
when "EPANDESC"
event = {}
@port.gets("\n") # ignore
event[:channel] = @port.gets("\n")[/Channel:(\S+)/, 1]
event[:channel_page] = @port.gets("\n")[/Channel Page:(\S+)/, 1]
event[:pan_id] = @port.gets("\n")[/Pan ID:(\S+)/, 1]
event[:addr] = @port.gets("\n")[/Addr:(\S+)/, 1]
event[:lqi] = @port.gets("\n")[/LQI:(\S+)/, 1]
event[:pair_id] = @port.gets("\n")[/PairID:(\S+)/, 1]
p event
callback_event(:EPANDESC, event)
buffer.clear
when "EEDSCAN"
@port.gets("\n") # ignore
_rssi = @port.gets("\n")
when "EPORT"
@port.gets("\n") # ignore
6.times do
_udp = @port.gets("\n") # ignore
end
@port.gets("\n") # ignore
4.times do
_tcp = @port.gets("\n") # ignore
end
@port.gets("\n") # "OK" ignore
when "EHANDLE"
@port.gets("\n") # ignore
while line = @port.gets("\n")
line.chomp!
break if line == "OK"
end
when "EVENT"
num, sender, param = *@port.gets("\n").sub(/\s+$/, '').split(/ /)
event = {
num: num,
sender: sender,
param: param
}
callback_event(:EVENT, event)
buffer.clear
when "EVER"
event = {}
event[:version] = @port.gets("\n").sub(/\s+$/, '')
callback_event(:EVER, event)
buffer.clear
when "EAPPVER"
event = {}
event[:version] = @port.gets("\n").sub(/\s+$/, '')
callback_event(:EAPPVER, event)
buffer.clear
else
# do nothing
end
when "\n"
# event 以外
line = buffer.chomp
@queue << line
buffer.clear
end
end
end
end
def command(string)
@port.write(string + "\r\n")
res = @queue.pop
if string.split(/ /)[0] == res.split(/ /)[0] # ignore echoback
res = @queue.pop
end
res
end
def on(name, &block)
(@event_callbacks[name.to_sym] ||= []) << block
end
private
def callback_event(name, event)
(@event_callbacks[name.to_sym] || []).each do |cb|
cb.call(event)
end
end
end
require 'logger'
require 'timeout'
class SmartMeterController
def initialize
@logger = Logger.new($stdout)
end
def start(io, opts)
@stack = SKSTACK_IP.new(io)
@events = Queue.new
@stack.on(:EVENT) do |e|
@logger.debug("EVENT %p" % e)
@events << e
end
@epandesc = nil
@stack.on(:EPANDESC) do |e|
@logger.debug("EPANDESC %p" % e)
@epandesc = e
end
@transactions = {}
@stack.on(:ERXUDP) do |e|
@logger.info("ERXUDP %p" % e)
begin
frame = ECHONET_Lite.parse_frame(e[:data])
if transaction = @transactions.delete(frame.tid)
transaction.call(frame)
end
rescue ECHONET_Lite::ParseError
@logger.info("Not an ECHONET Lite frame")
end
end
@stack.on(:EVER) do |e|
@logger.info("EVER %p" % e)
end
@stack.on(:EAPPVER) do |e|
@logger.info("EAPPVER %p" % e)
end
@stack.command("SKRESET") == "OK" or raise
@stack.command("SKVER") == "OK" or raise
@stack.command("SKAPPVER") == "OK" or raise
@stack.command("SKSREG SFE 0") == "OK" or raise
@logger.info("Setting ID and Password")
@stack.command("SKSETPWD C #{opts[:PASS]}") == "OK" or raise
@stack.command("SKSETRBID #{opts[:ID]}") == "OK" or raise
while true
@logger.info("Scanning device...")
@stack.command("SKSCAN 2 FFFFFFFF 6")
while e = @events.pop
if e[:num].to_i(16) == SKSTACK_IP::EVENT_COMPLETED_ACTIVE_SCAN
@logger.info("Scan Completed")
break
end
end
if @epandesc
break
end
@logger.info("Device not found... retrying...")
sleep 1
end
@logger.info("Device found %p" % @epandesc)
@logger.info("Getting IPv6 Address from MAC Address (%p)" % @epandesc[:addr])
@ipv6_addr = @stack.command("SKLL64 #{@epandesc[:addr]}")
@logger.info("Setting Channel and Pan ID")
@stack.command("SKSREG S2 #{@epandesc[:channel]}") == "OK" or raise
@stack.command("SKSREG S3 #{@epandesc[:pan_id]}") == "OK" or raise
@logger.info("Starting PANA")
@stack.command("SKJOIN #{@ipv6_addr}") == "OK" or raise
while e = @events.pop
case e[:num].to_i(16)
when SKSTACK_IP::EVENT_PANA_COMPLETED
break
when SKSTACK_IP::EVENT_PANA_ERROR
raise "pana error"
end
end
@logger.info("PANA Completed")
@tid = 0
end
def retrieve_power
@tid += 1
tid = @tid
q = Queue.new
@transactions[tid] = proc {|frame|
q << frame
}
frame = ECHONET_Lite::Frame.new(
ECHONET_Lite::EHD1,
ECHONET_Lite::EHD2_DEFINED,
@tid,
ECHONET_Lite::EDATA.new(
ECHONET_Lite::EOJ.new(0x05, 0xFF, 0x01),
ECHONET_Lite::EOJ.new(0x02, 0x88, 0x01),
0x62,
1,
[
ECHONET_Lite::Property.new(
0xe7,
0x00,
""
)
]
)
)
handle = 1
port_num = 3610
sec = 1
data = frame.pack
p [:packed, data]
@stack.command("SKSENDTO %s %s %04X %s %04X %s" % [
handle,
@ipv6_addr,
port_num,
sec,
data.length,
data
])
while e = @events.pop
if e[:num].to_i(16) == SKSTACK_IP::EVENT_UDP_SENT
unless e[:param].to_i(16) == 0 # success
return nil
end
break
end
end
ret = nil
begin
Timeout.timeout(5) do
ret = q.pop
end
rescue Timeout::Error
@logger.info "UDP Response Timeout"
@transactions.delete(tid)
end
ret
end
end
io = nil
if ENV["PORT"].nil?
require 'socket'
s1, s2 = Socket.pair(:UNIX, :STREAM, 0)
Thread.start do
while l = s2.gets
l.chomp!
case l
when "SKVER"
s2 << "SKVER\r\n"
s2 << "EVER 1.2.10\r\n"
s2 << "OK\r\n"
when "SKSREG SFE 0"
s2 << "SKSREG SFE 0\r\n"
s2 << "OK\r\n"
when /^SKSETPWD/
s2 << "OK\r\n"
when /^SKSETRBID/
s2 << "OK\r\n"
when "SKSCAN 2 FFFFFFFF 6"
s2 << "OK\r\n"
s2 << "EVENT 20 FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX\r\n"
s2 << "EPANDESC\r\n"
s2 << " Channel:2F\r\n"
s2 << " Channel Page:09\r\n"
s2 << " Pan ID:A0E6\r\n"
s2 << " Addr:001C64000357XXXX\r\n"
s2 << " LQI:84\r\n"
s2 << " PairID:00AXXXXX\r\n"
s2 << "EVENT 22 FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX\r\n"
when /^SKLL64/
s2 << "FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY\r\n"
when /^SKSREG S2/
s2 << "OK\r\n"
when /^SKSREG S3/
s2 << "OK\r\n"
when /^SKJOIN/
s2 << "OK\r\n"
s2 << "EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 02\r\n"
s2 << "EVENT 02 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY\r\n"
s2 << "ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0028 (����O�y\r\n"
s2 << "EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00\r\n"
s2 << "ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0068 h����O�z$�r%^a�;H)��#L�8�8/�4+�u\-����&ѨSM00000099021000000000000000AXXXXX\r\n"
s2 << "EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00\r\n"
s2 << "ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0054 T����O�{;�;/��4+�u\-����&Ѩ��?s�����r��2���0��D�R��\r\n"
s2 << "EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00\r\n"
s2 << "ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0058 X����O�|� Q�{��(F���.�[�<\r\n"
s2 << "EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00\r\n"
s2 << "EVENT 25 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY\r\n"
when /SKSENDTO/
s2 << "ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 0E1A 0E1A 001C64000357XXXX 1 0012 \x10\x81\x00\x01\x02\x88\x01\x05\xFF\x01r\x01\xE7\x04\x00\x00\x04Z\r\n"
end
end
end
io = s1
else
require 'serialport'
begin
io = SerialPort.new(
"/dev/tty.usbserial-A500YQPG",
115200,
8,
1,
0
)
rescue Errno::EBUSY
sleep 1
retry
end
end
c = SmartMeterController.new
c.start(io, {
ID: "0000 00XX 0XXX 0000 0000 0000 XXXX XXXX".gsub(/ /, ''),
PASS: "XXXX XXXX XXXX".gsub(/ /, ''),
})
loop do
frame = c.retrieve_power
unless frame
puts "failed to get power"
next
end
frame.edata.properties.each do |prop|
p prop
if prop.epc == 0xe7 && prop.pdc == 4
watts = prop.edt.unpack("N")[0]
p "#{watts} W"
end
end
end
先週火曜日は体調不良で休んだが、子供も熱を出してひきとることになったので、結局完全には休めなかった。
鼻炎と喉がすこし痛いぐらいなので耳鼻科にいって薬をもらっているけど治らない。というか鼻炎と喉はともかく全身倦怠感がひどくてなにもできない。
とりあえずやってみたレベルですが、Bルートサービスが利用開始できたので瞬間電力を読むところまでやってみました。
あたりがポイントです。
混んでることはわかっていたのであまり期待せずに申し込んでいます。スマートメータに変更していない状態で申し込んでおり、途中でスマートメータ切替工事が入るパターンです。
関東在住ですので、東京電力パワーグリッドの管轄です。
できれば工事を見学をしたかったけど、帰宅したら替わってしまっていた。
ウェブの電気家計簿を使っている場合、ログインして以下のURLにアクセスするとわかります。
https://www.kakeibo.tepco.co.jp/dk/wmf/meterInfoReference/
電気家計簿を使ってない場合、検針票に書いてあると思います。
Wi-SUN モジュールは今のところ個人でも手に入るのはロームのものしかなさそう。News Detail に書いてある通り。技適付きなので心配いらない。
RS Online で BP35A1, BP35A7, BP35A7 - accessories を買おうとしたが入手困難といわれてダメで、BP35A7 - accessories だけ送られてきて辛い。チップワンストップ だと在庫があった…… 個人とは取引しないと書いてあるが無視して個人事業主ということで登録して買った。
BP35A7 は既に廃盤?で、BP35A7A というのがある。BP35A1はそのまま。よくわからないがまとめて入手する方法がすくない。
マザーボードとして BP359C というのがあるが、これはUSBシリアル変換とかがついてるだけなので、あまり必要なさそう。
Amazon でもなぜか取り扱いがあって (マーケットプレイスではなく Amazon.co.jp 販売)
ROHM 無線通信モジュール BP35A1 cho45
ROHM BP35A7A cho45
Amazon で買う場合 BP35A7 - accessories は高価すぎるので買わずに別のところで買ったほうがよさそう。BP35A7もなぜか高い。が、在庫探しが面倒なら買ってもいいのではないか…
BP35A1 についているコネクタに対応するコネクタは 20P3.0-JMCS-G-TF という JST のコネクタ。Digikey で 120円ぐらいで売っているので、Digikey を利用する際に買っておけばBP35A7相当品を自作できるが、基板設計とか考えるとやはり面倒なのとそこまで高価ではないので素直に買ったほうが良いでしょう。
どうも結構今だと高いので辛い感じがしますがそのうち安いプロダクトがでると信じたい。
最低限使うのに必要な配線は
だけです。電源電圧は3.3Vなので注意。
UART 経由でコマンドを打てば良いので、モジュールとUSB-UART変換さえあればPCで簡単に試せます。
モジュールの仕様書などは「ROHM Sub-GHzシリーズ」サポートページというところから辿れる。
サンプルも用意されているし、コマンドリファレンスも親切に書いてある。
Wi-SUN 自体は国際規格化されているけど、日本のスマートメータ用に産まれたというそもそもの経緯があるので、今のところ日本以外で需要がない。なのでモジュール自体が少ない。
Wi-SUN の認証を通っているのはウェブから一覧でみれる。ECHONET Route B から辿ればよさそう。ロームの以外にもあるはあるけど、手に入らない。
アプリケーションレイヤーでのプロトコルは ECHONET Lite というものです。Wi-SUN の OSI参照モデルでの関係はWi-SUN ECHONET Profile 準拠通信制御ソフトウェア がわかりやすいです。
BP35A1 モジュールでは物理層からトランスポート層(TCP/UDP)及びセッション層(PANA : Protocol for Carrying Authentication for Network Access)までのサポートがありますので、実際の必要なのはアプリケーション層の実装のみです。
仕様書は普通に公開されていて、しかも日本語です。とりあえず必要なのは「第2部 ECHONET Lite 通信ミドルウェア仕様」で、具体的には ECHONET Lite のフレーム構造を理解していればとりあえず通信できます。
ECHONET Lite は概念的には BLE の GATT に似たような仕組みです。「それぞれの機器のあるプロパティを読み書きする」ことができます。
全体的な処理の流れを Ruby で書いてみました。
このコード自体は例外を考慮しておらず全く応用性はありませんが、プロトコルの理解のためにはある程度有用だと思います。ECHONET Lite 部分に細かくコメントをつけています。
ハマりポイント
require 'serialport'
begin
@port = SerialPort.new(
"/dev/tty.usbserial-A500YQPG",
115200,
8,
1,
0
)
rescue Errno::EBUSY
sleep 1
retry
end
puts "init"
def @port.send(line)
$stdout.puts ">> #{line}"
self.write(line + "\r\n")
end
def @port.wait(val)
while
line = self.gets.chomp
$stdout.puts "<< #{line}"
if val === line
return Regexp.last_match
end
end
end
@port.set_encoding(Encoding::BINARY)
@port.send "SKVER\r\n"
@port.wait "OK"
# エコーバックをオフに
@port.send "SKSREG SFE 0\r\n"
@port.wait "OK"
# スペース区切りで通知されるが、実際は削除する
ROUTE_B_ID = "0000 0099 0210 0000 0000 0000 00XX XXXX".gsub(/ /, '')
ROUTE_B_PASS = "XXXX XXXX XXXX".gsub(/ /, '')
@port.send "SKSETPWD C #{ROUTE_B_PASS}"
@port.wait 'OK'
@port.send "SKSETRBID #{ROUTE_B_ID}"
@port.wait 'OK'
info = {}
@port.send 'SKSCAN 2 FFFFFFFF 6'
info[:sender] = @port.wait(/^EVENT 20 (?<sender>.+)/)[1]
@port.wait(/^EPANDESC/)
info[:channel] = @port.wait(/^ Channel:(?<channel>.+)/)[1]
info[:channel_page] = @port.wait(/^ Channel Page:(?<channel_page>.+)/)[1]
info[:pan_id] = @port.wait(/^ Pan ID:(?<pan_id>.+)/)[1]
# MACアドレス
info[:addr] = @port.wait(/^ Addr:(?<addr>.+)/)[1]
info[:lqi] = @port.wait(/^ LQI:(?<lqi>.+)/)[1]
info[:pair_id] = @port.wait(/^ PairID:(?<pair_id>.+)/)[1]
p info
#<< Channel:2F
#<< Channel Page:09
#<< Pan ID:A0E6
#<< Addr:00XXXXXXXXXXXXXX
#<< LQI:7D
#<< PairID:00XXXXXX
@port.wait(/^EVENT 22/)
# macアドレスをipv6 アドレスへ変換
@port.send "SKLL64 #{info[:addr]}"
info[:ipv6_addr] = @port.wait(/[0-9A-F:]+/)
# channel
@port.send "SKSREG S2 #{info[:channel]}"
@port.wait "OK"
# pan id
@port.send "SKSREG S3 #{info[:pan_id]}"
@port.wait "OK"
@port.send "SKJOIN #{info[:ipv6_addr]}"
# 0x25:PANA による接続が完了した
@port.wait(/^EVENT 25/)
@tid = 0
while true
# (1)Layer4 で UDP(User Datagram Protocol)、Layer3 で IP(Internet Protocol)、
# を使用する場合
# 各 ECHONET Lite ノードは、それぞれ IP アドレスを持つ。IP アドレスの範囲、
# 取得方法は規定しない。1つの ECHONET Lite フレームは、1つの UDP パケッ
# トにて転送する。UDP パケットにおける送信先 PORT 番号は、要求・応答・通知
# 等の種別に関わらず、常に 3610 とする。
handle = 1
port_num = 3610
sec = 1 # 暗号化有効・有効でなければ送信しない
# 上記の通り data は ECHONET Lite フレームとなる
# ref. https://echonet.jp/wp/wp-content/uploads/pdf/General/Standard/ECHONET_lite_V1_12_jp/ECHONET-Lite_Ver.1.12_02.pdf
### ref. https://echonet.jp/wp/wp-content/uploads/pdf/General/Standard/Release/Release_G_revised/Appendix_G_revised.pdf
@tid += 1
data = [
# EHD1 = ECHONET Lite 1 byte
0b00010000,
# EHD2 = 既定形式 1 byte
0x81,
# TID - トランザクションID 2 bytes
@tid,
# EDATA
## SEOJ - 送信元ECHONET Liteオブジェクト指定 3 bytes
### Class Group Code - 管理・操作関連機器クラスグループ
0x05,
### Class Code - コントローラ
0xFF,
### Instance Code
0x01,
## DEOJ - 相手先ECHONET Liteオブジェクト指定 3 bytes
### Class Group Code - 住宅・設備関連機器クラスグループ
0x02,
### Class Code - 低圧スマート電力量メータ
0x88,
### Instance Code
0x01,
## ESV - ECHONET Lite サービス 1 byte
## プロパティ値読み出し要求
0x62,
## OPC - 処理プロパティ数
0x01,
### EPC - プロパティ - 瞬時電力計測値
#### 電力実効値の瞬時値を 1W 単位で示す。(結果は 4 bytes singed long)
0xe7,
### PDC - EDTのバイト数
0x00,
### EDT - プロパティデータ
# なし
].pack("CCn CCC CCC C C CC".gsub(" ", ""))
p data
@port.send "SKSENDTO %s %s %04X %s %04X %s" % [
handle,
info[:ipv6_addr],
port_num,
sec,
data.length,
data
]
# TODO use datalen to read
res = @port.wait(/^ERXUDP (?<sender>\S+) (?<dest>\S+) (?<rport>\S+) (?<lport>\S+) (?<senderlla>\S+) (?<secured>\S+) (?<datalen>\S+) (?<data>\S+)/)
p res
# まず接続後にインスタンスリスト通知 がくる
# \x10\x81\x00\x00
# \x0E\xF0\x01 ノードプロファイル
# \x0E\xF0\x01 ノードプロファイル
# \x73 プロパティ値通知
# \x01 1つ
# \xD5
# \x04 4バイト
# \x01\x02\x88\x01
#
# "\x10\x81\x00\x00\x0E\xF0\x01\x0E\xF0\x01s\x01\xD5\x04\x01\x02\x88\x01"
p res[:data][-4..-1].unpack("N")
sleep 3
end
@port.send "SKTERM"
@port.wait "ENT 27" 実行すると以下のようになります。一部アドレスなどは念のため置き換えています。最後のほうに出てくる[1097]が瞬間消費電力です。
init
>> SKVER
<< SKVER
<< EVER 1.2.10
<< OK
>> SKSREG SFE 0
<< SKSREG SFE 0
<< OK
>> SKSETPWD C XXXXXXXXXXXX
<< OK
>> SKSETRBID 000000000000000000000000000000XX
<< OK
>> SKSCAN 2 FFFFFFFF 6
<< OK
<< EVENT 20 FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX
<< EPANDESC
<< Channel:2F
<< Channel Page:09
<< Pan ID:A0E6
<< Addr:001C64000357XXXX
<< LQI:84
<< PairID:00AXXXXX
{:sender=>"FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX", :channel=>"2F", :channel_page=>"09", :pan_id=>"A0E6", :addr=>"001C64000357XXXX", :lqi=>"84", :pair_id=>"00AXXXXX"}
<< EVENT 22 FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX
>> SKLL64 001C64000357XXXX
<< FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY
>> SKSREG S2 2F
<< OK
>> SKSREG S3 A0E6
<< OK
>> SKJOIN FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY
<< OK
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 02
<< EVENT 02 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0028 (����O�y
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0068 h����O�z$�r%^a�;H)��#L�8�8/�4+�u\-����&ѨSM00000099021000000000000000AXXXXX
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0054 T����O�{;�;/��4+�u\-����&Ѩ��?s�����r��2���0��D�R��
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 02CC 02CC 001C64000357XXXX 0 0058 X����O�|� Q�{��(F���.�[�<
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< EVENT 25 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY
"\x10\x81\x00\x01\x05\xFF\x01\x02\x88\x01b\x01\xE7\x00"
>> SKSENDTO 1 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 0E1A 1 000E ���b�
<<
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< OK
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FF02:0000:0000:0000:0000:0000:0000:0001 0E1A 0E1A 001C64000357XXXX 1 0012 ���s��
#<MatchData "ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FF02:0000:0000:0000:0000:0000:0000:0001 0E1A 0E1A 001C64000357XXXX 1 0012 \x10\x81\x00\x00\x0E\xF0\x01\x0E\xF0\x01s\x01\xD5\x04\x01\x02\x88\x01" sender:"FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY" dest:"FF02:0000:0000:0000:0000:0000:0000:0001" rport:"0E1A" lport:"0E1A" senderlla:"001C64000357XXXX" secured:"1" datalen:"0012" data:"\x10\x81\x00\x00\x0E\xF0\x01\x0E\xF0\x01s\x01\xD5\x04\x01\x02\x88\x01">
[16943105]
"\x10\x81\x00\x02\x05\xFF\x01\x02\x88\x01b\x01\xE7\x00"
>> SKSENDTO 1 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 0E1A 1 000E ���b�
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 0E1A 0E1A 001C64000357XXXX 1 0012 ���r�Z
#<MatchData "ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 0E1A 0E1A 001C64000357XXXX 1 0012 \x10\x81\x00\x01\x02\x88\x01\x05\xFF\x01r\x01\xE7\x04\x00\x00\x04Z" sender:"FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY" dest:"FE80:0000:0000:0000:021D:1290:0003:A4F1" rport:"0E1A" lport:"0E1A" senderlla:"001C64000357XXXX" secured:"1" datalen:"0012" data:"\x10\x81\x00\x01\x02\x88\x01\x05\xFF\x01r\x01\xE7\x04\x00\x00\x04Z">
[1114]
"\x10\x81\x00\x03\x05\xFF\x01\x02\x88\x01b\x01\xE7\x00"
>> SKSENDTO 1 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 0E1A 1 000E ���b�
<<
<< EVENT 21 FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY 00
<< OK
<< ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 0E1A 0E1A 001C64000357XXXX 1 0012 ���r�I
#<MatchData "ERXUDP FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY FE80:0000:0000:0000:XXXX:XXXX:XXXX:XXXX 0E1A 0E1A 001C64000357XXXX 1 0012 \x10\x81\x00\x02\x02\x88\x01\x05\xFF\x01r\x01\xE7\x04\x00\x00\x04I" sender:"FE80:0000:0000:0000:YYYY:YYYY:YYYY:YYYY" dest:"FE80:0000:0000:0000:021D:1290:0003:A4F1" rport:"0E1A" lport:"0E1A" senderlla:"001C64000357XXXX" secured:"1" datalen:"0012" data:"\x10\x81\x00\x02\x02\x88\x01\x05\xFF\x01r\x01\xE7\x04\x00\x00\x04I">
[1097] 実際はイベントや UDP の処理を適切に書く必要があります。ちゃんとやらないとダメなので、適切なライブラリがあると嬉しそうです。
dot by dot だと細かすぎると感じることがあるが、だからといって高解像度設定だと狭すぎる。(結局 dot by dot で使ってる)
ということで、5K が本命だなと感じている。
Dell ディスプレイ モニター UP2715K 27インチ/5K/IPS低反射/8ms/MimiDPx1,TwinDPx1/AdobeRGB 99%/USBハブ/スピーカ内蔵/3年間保証 cho45
最近まで 5K は DELL の 27インチが20万ぐらいという感じだったが、いつのまにか HP Z27q 5K というのも出ていて、これがだいぶ安い。
どちらも AdobeRGB 99% の色域。
今うちのモニタは 27インチ 2560x1440 (AdobeRGB) と 24インチ 4K (sRGB) なので、2560x1440 を 5K に単純に置き換えられそう。なんだけど、現実的には以下の点で難しい。
モニタの進化についていけてない……
結構前にAMP 対応しようと思ったけどやめたときのメモを掘り起こしてポストしておく。
AMP のチュートリアル的なやつ数回眺めて「なんか(標準として)イマイチだなー」と感じつつ、 Google がサポートするなら一回試すぐらいはしようと思いやってみましたが、対応を見送りました。
https://www.ampproject.org/docs/get_started/technical_overview.html 見ると、別に AMP だからできるのだ!っていう機能はない。
AMPには2つの要素が同居している
後者はつまり AMP を使っている限り悪意のあるスクリプトのあるページにはなりませんよという保証。
検索流入に特化するならメリットになる。Google の CDN 経由で配信されるのが大きい。
しかし、似たような構成 (特にいえばJS無効の) のページのロード時間ってそもそも遅くない。コネクションにかかる時間分の速度向上のために、わざわざ特殊なマークアップで書くメリットはあるだろうか。
結局 AMP がやってることって「JSなしのページのキャッシュ・プリロード」+「オレサマのJSなら特別に実行してやっても良いぞ」みたいな感じなので、そのために変なカスタムエレメントとか入れてんの? レイアウトまわりにCSS以外の概念入れんの?? という疑念が晴れない。
元々 Cache-Control: public という便利なのがあるのだから、その場合はキャッシュ済みのを CDN から配信するのを優先したらいいだけじゃないか? 既存技術の延長でなんとかできる範囲ではなかったのだろうか? 任意スクリプトってのが最大の問題だけど、AMPならオッケーってのはどうなのか?
ベンダープリフィックスつきのボイラープレートをいちいち書かされるのも意味不明。新しいベンダー出てきたらどうすんの?
カスタムエレメントも、amp-twitter とか amp-facebook とか、どういうつもりで追加してるのかわからないエレメントがたくさんある。いろんなサービスが「カスタムエレメントを定義してくれ」といったら対応コードが無限に増えていくんでしょうか。amp-ad も、メジャーな広告ネットワークをサポートしているけど、そもそもサポートする広告ネットワークを指定されてるのが気にくわない。いろんな無限のアドネットワークがが「ウチにも対応してくれ」といったら対応コードが無限に増えていくんでしょうか。
と、だんだんイライラしてきたのでやめて、別の見方をしてみることにします。
あたりを考えると、変なJSライブラリを使うよりはマシそうな雰囲気があります。この捉えかたで多少心が落ち着きました。
「AMP とは準 static ページを作るためのJSフレームワーク」であって、Google が対応済みという大きなメリットがある! 万歳!!! Google が対応済みってのがとにかく最高!!!
デジタルとアナログだと1ケタ精度が違うのだけど、デジタルだとその分取り扱いに気をつける必要があってちょっと面倒だったりする。デジタルノギスは箱に入れて保管しているので、雑に計りたいときは結局雑に使えるアナログしか使わない。そして殆どのケースで精度は必要なくて雑に計ればことたりてしまう。
デジタルノギスを使うのは結局、現物しかないものの寸法を図面に起こすときぐらいしかない。全く使ってないわけではないから無駄とまではいえないけど、そんなに必要ではなかったな、という感想。
あとそもそも買ったデジタルノギスはいまいちすべりが悪くて使いにくい……
どのOSでもレンダリングは遅くて、多少乱れるので、OS X だから遅いのかな〜とか考える必要はない。
どのOSでもレンダリングは遅くて、多少乱れるので、OS X だから遅いのかな〜とか考える必要はない。