引き続きIoTエンジニア養成読本のハンズオンの内容を実践中なわけですが、今度はSORACOM AirのメタデータとLEDの点灯を連動させてる処理をRubyで実装してみます。
ユーザーコンソールからの設定
メタデータサービスを使うにはまずユーザコンソールから、グループ設定とメタデータサービスの使用設定をしておく必要があります。
ユーザコンソールのメニューからグループを作成した後、そのグループのSORACOM Airの設定で、メタデータサービスの使用設定をONにし、Readonlyのチェックを外して設定を保存します。
次にSORACOM AirのSim管理画面から、該当のSimのグループを先ほど作成したグループに変更して設定を保存します。
SORACOM Air のメタデータサービスに接続
まずはSORACOM Airで3Gネットワークに接続します。
pi@raspberrypi:~ $ sudo /usr/local/sbin/connect_air.sh & [1] 30291 pi@raspberrypi:~ $ Found AK-020 waiting for modem device --> WvDial: Internet dialer version 1.61 --> Cannot get information for serial port. --> Initializing modem. --> Sending: ATZ ATZ OK --> Sending: ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0 ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0 OK --> Sending: AT+CGDCONT=1,"IP","soracom.io" AT+CGDCONT=1,"IP","soracom.io" OK --> Modem initialized. --> Sending: ATD*99***1# --> Waiting for carrier. ATD*99***1# OK CONNECT 21000000 --> Carrier detected. Starting PPP immediately. --> Starting pppd at Thu May 4 05:36:43 2017 --> Pid of pppd: 30314 --> Using interface ppp0 --> local IP address 10.247.81.162 --> remote IP address 10.64.64.64 --> primary DNS address 100.127.0.53 --> secondary DNS address 100.127.1.53
続いてcurlで直接メタデータサービスに接続してみます。(レスポンスの内容は省略しています)
pi@raspberrypi:~ $ curl http://metadata.soracom.io/v1/subscriber {...}
SORACOM Airでネットワークに接続していないとメタデータサービスにはアクセスできません。
レスポンスのjsonを整形してみると下記のようになります。(一部マスクしています)
{ "apn": "soracom.io", "createdAt": 1493055578551, "createdTime": 1493055578551, "expiredAt": null, "expiryAction": null, "expiryTime": null, "groupId": "d79b3210-8d23-4a41-8003-6b6acdec5e55", "iccid": "XXXXXXXXXXXXXXXXXX", "imeiLock": null, "imsi": "XXXXXXXXXXXXX", "ipAddress": "10.XXX.XX.XXX", "lastModifiedAt": 1493876507132, "lastModifiedTime": 1493876507132, "moduleType": "nano", "msisdn": "XXXXXXXXXXX", "operatorId": "OPXXXXXXXXX", "plan": 0, "serialNumber": "AXXXXXXXXXXXXX", "sessionStatus": { "dnsServers": [ "100.127.0.53", "100.127.1.53" ], "gatewayPublicIpAddress": "54.XXX.XXX.XX", "imei": "XXXXXXXXXXXXX", "lastUpdatedAt": 1493876215192, "location": null, "online": true, "ueIpAddress": "10.XXX.XX.XXX" }, "speedClass": "s1.slow", "status": "active", "tags": {}, "terminationEnabled": false, "type": "s1.slow" }
取得できるデータの特定の項目だけ取得したい場合は下記のようにURLの末尾に項目名を追加します。
pi@raspberrypi:~ $ curl http://metadata.soracom.io/v1/subscriber.type s1.slow
メタデータの更新
メタデータのタグはAPIで取得だけでなく更新も可能です。curlでJSON形式でPUTリクエストを送信してみます。
pi@raspberrypi:~ $ curl http://metadata.soracom.io/v1/subscriber.tags {} pi@raspberrypi:~ $ pi@raspberrypi:~ $ curl -X PUT -H content-type:application/json -d '[{"tagName":"led","tagValue" :"off"}]' http://metadata.soracom.io/v1/subscriber/tags {...} pi@raspberrypi:~ $ pi@raspberrypi:~ $ curl http://metadata.soracom.io/v1/subscriber.tags {"led":"off"} pi@raspberrypi:~ $ pi@raspberrypi:~ $ curl http://metadata.soracom.io/v1/subscriber.tags.led off pi@raspberrypi:~ $
メタデータのタグ情報によってLEDの状態を変更する
それではRubyスクリプトからメタデータサービスにアクセスして、タグの内容によってLEDを点灯/消灯してみます。
require 'bundler/setup' require 'pi_piper' require 'open-uri' interval = 60.0 unless ARGV.empty? interval = ARGV[0].to_f end led_pin = PiPiper::Pin.new(pin: 22, direction: :out) loop do print 'Connecting to Meta-data service... ' begin res = OpenURI.open_uri('http://metadata.soracom.io/v1/subscriber.tags.led', read_timeout: 5) code = res.status.first.to_i if code != 200 puts "ERROR: Invalid response code: #{code} message: #{res.status[1]}" break end led_tag = res.read.rstrip if led_tag.downcase == 'off' puts 'LED tag is OFF. Turn off the LED.' led_pin.off elsif led_tag.downcase == 'on' puts 'LED tag is ON. Turn on the LED.' led_pin.on end rescue => e puts e.message puts e.backtrace.join("\n") break end if interval > 0 sleep(interval) next end break end
実行結果は下記のようになります。最初はonだったタグ情報をユーザコンソールからoffに変更すると、LEDが消灯されます。またonに変更すると、LEDが点灯されます。
pi@raspberrypi:~ $ sudo bundle exec ruby degital_twin1.rb 10 Connecting to Meta-data service... LED tag is ON. Turn on the LED. Connecting to Meta-data service... LED tag is ON. Turn on the LED. Connecting to Meta-data service... LED tag is ON. Turn on the LED. Connecting to Meta-data service... LED tag is ON. Turn on the LED. Connecting to Meta-data service... LED tag is OFF. Turn off the LED. ← この直前にユーザコンソールからタグの値をoffに変更 Connecting to Meta-data service... LED tag is OFF. Turn off the LED. Connecting to Meta-data service... LED tag is ON. Turn on the LED. ← この直前にユーザコンソールからタグの値をonに変更 Connecting to Meta-data service... LED tag is ON. Turn on the LED.
LEDの状態をメタデータに反映する
次は、スイッチが押されたらLEDのON/OFFを切り替え、その情報をメタデータの方にも反映します。
require 'bundler/setup' require 'pi_piper' require 'net/http' require 'open-uri' interval = 60.0 unless ARGV.empty? interval = ARGV[0].to_f end led_pin = PiPiper::Pin.new(pin: 22, direction: :out) led_pin.off switch_pin = PiPiper::Pin.new(pin: 23, direction: :in, pull: :up) start_time = nil loop do start_time = Time.now.to_i print '- Connecting to Meta-data service... ' begin res = OpenURI.open_uri('http://metadata.soracom.io/v1/subscriber.tags.led', read_timeout: 5) code = res.status.first.to_i if code != 200 puts "ERROR: Invalid response code: #{code} message: #{res.status[1]}" break end led_tag = res.read.rstrip if led_tag.downcase == 'off' puts 'LED tag is OFF. Turn off the LED.' led_pin.off elsif led_tag.downcase == 'on' puts 'LED tag is ON. Turn on the LED.' led_pin.on end rescue => e puts e.message puts e.backtrace.join("\n") break end puts "- Waiting input via the switch (%.1f sec)" % (start_time + interval - Time.now.to_i) loop do switch_pin.read led_pin.read if switch_pin.value == 0 puts "The switch has been pushed. Turn %s the LED" % (led_pin.off? ? 'ON' : 'OFF') led_pin.off? ? led_pin.on : led_pin.off led_pin.read print 'Updating Meta-data... ' payload = '[{"tagName":"led","tagValue":"%s"}]' % (led_pin.on? ? 'on' : 'off') uri = URI.parse('http://metadata.soracom.io/v1/subscriber/tags') http = Net::HTTP.new(uri.host, uri.port) req = Net::HTTP::Put.new(uri.path, initheader = { 'Content-Type' => 'application/json'}) req.body = payload res = http.start {|http| http.request(req) } puts "response_code: #{res.code}" end if Time.now.to_i > start_time + interval break end sleep(0.1) end end
実行結果は下記の通りです。30秒ごとにメタデータサービスからタグ情報を取得していますが、その間にスイッチが押された場合はその情報をメタデータサービスに反映しています。
pi@raspberrypi:~ $ sudo bundle exec ruby degital_twin2.rb 30 - Connecting to Meta-data service... LED tag is ON. Turn on the LED. - Waiting input via the switch (29.0 sec) - Connecting to Meta-data service... LED tag is ON. Turn on the LED. - Waiting input via the switch (29.0 sec) The switch has been pushed. Turn OFF the LED ← スイッチを押下 Updating Meta-data... response_code: 200 - Connecting to Meta-data service... LED tag is OFF. Turn off the LED. - Waiting input via the switch (29.0 sec) The switch has been pushed. Turn ON the LED ← スイッチを押下 Updating Meta-data... response_code: 200 - Connecting to Meta-data service... LED tag is ON. Turn on the LED. - Waiting input via the switch (29.0 sec)