Yado_tech

旅館+ITとはなんぞ

車のQOLが爆上がりして優勝できるやつつくった。

M5Stackを買いました。

www.switch-science.com


これはArduino+ボタン+液晶+SDカードリーダーを1つにまとめたもの

ブレッドボードなしに色々できるので電子工作のハードルを一気に下げてくれるすぐれものです。

こちらで画像のようなものを作りました。

http://pic.twitter.com/6MBtczmH2wpic.twitter.com

仕組みはM5Stackをブルートゥースキーボードとして動かしてキーを送信しているだけです。
Bluetoothキーボードはこちらのライブラリをインクルードして使いました。

github.com

あとはこのような画像を用意して

f:id:devilmakelie:20200523083150j:plain

以下のようなコードを作るだけです。

#include <BleConnectionStatus.h>
#include <BleKeyboard.h>
#include <KeyboardOutputCallbacks.h>

#include <M5Stack.h>
BleKeyboard bleKeyboard("Spotify Controller");
void setup() {
  M5.begin();
  M5.Lcd.drawJpgFile(SD,"/spotify.jpg");
 
  bleKeyboard.begin();

}

void loop() {
  M5.update();
  if(bleKeyboard.isConnected()){
    //Backword
    if(M5.BtnA.wasPressed()){
      bleKeyboard.write(KEY_MEDIA_PREVIOUS_TRACK);
            }
    //Play, Pause
    if(M5.BtnB.wasPressed()){
      bleKeyboard.write(KEY_MEDIA_PLAY_PAUSE);
      }
    //FastForword
    if(M5.BtnC.wasPressed()){
      bleKeyboard.write(KEY_MEDIA_NEXT_TRACK);
      
      }
    //wait

    delay(100);
    
    }

Arduinoだと起動が早いので車との相性が抜群だと思いました。

お風呂に温度異状があった場合にスマートライトの色を変える。GAS版

tuya Smart Life がIFTTTと連携しなくなるということでびっくりした話。

youtu.be

同時にこういった記事も見つけた。

qiita.com

こちらの記事ではnode.jsからtuya apiにアクセスしていたが、サーバーを用意するのもまだるっこしいので

GASで書いてみた。

必要なもの

  • おんどとりの温度計

データロガー おんどとり | SMART VALVE | T&D Corporation

  • スマートLED(私は2つで3,000円のこちらを購入した)



この辺は先程挙げた記事の中にやり方は書いてあります。

これで以下のようなGASを書いて5分ごとに実行すればOKです。

//TUYA API 設定 環境に応じて書き換えて下さい。
const clientId = "[CLIENTID]";
const clientSecret = "CLIENTSECRET";
const device_id = ["DEVICE_A", "DEVICE_B"];

//おんどとりweb storage API 設定
//環境に応じて書き換えて下さい。
const api_key = "API_KEY";
const login_id = "LOGIN_ID";
const password = "PASSWORD";
//>>>>【重要】最後にtemps関数内の風呂温度の内容を書き換えてください。<<<<<
//

//温度を配列で返す関数
function temps() {
  const ondotori_url = "https://api.webstorage.jp/v1/devices/current";

  const furo_temp = () => {
    var paylord = {
      "api-key": api_key,
      "login-id": login_id,
      "login-pass": password,
    };
    var headers = {
      "X-HTTP-Method-Override": "GET",
      "Content-Type": "application/json",
    };
    var options = {
      method: "post",
      payload: JSON.stringify(paylord),
      headers: headers,
      muteHttpExceptions: true,
    };

    return UrlFetchApp.fetch(ondotori_url, options);
  };
  return JSON.parse(furo_temp());
}

//ここまで関数

//ここから本文
function myfunction() {
  //温度のJSONを取得する
  var tmprs = temps();

  //デバッグ用 女子風呂の温度
  //Logger.log("女子:" + tmprs["devices"][1]["channel"][0].value)

  //↓↓↓男子風呂の温度 環境に応じて切り替えて下さい
  var danshi = tmprs["devices"][2]["channel"][0].value;

  //↓↓↓女子風呂の温度 環境に応じて切り替えて下さい
  var joshi = tmprs["devices"][1]["channel"][0].value;

  if (Math.max(danshi, joshi) > 43) {
    Logger.log(`熱い:男子:${danshi} 女子:${joshi}`);

    setColour(colour.red);
  } else if (Math.min(danshi, joshi) < 40) {
    Logger.log(`冷たい:男子:${danshi} 女子:${joshi}`);

    setColour(colour.blue);
  } else {
    Logger.log(`普通:男子:${danshi} 女子:${joshi}`);
    setColour(colour.green);
  }

  //if (Math.min(danshi,joshi)<38 && Math.max(danshi,joshi)>44){
  //  Logger.log("なんか変")
  //  status = "somethingwrong"
  //}
}
//ここまで本文

//以降はTUYA API用スクリプト
//setColour(colour.red or colour.blue or colour.green)以外はエラーとなります。
//単純に動かないだけ。

var url = "https://openapi.tuyaus.com/v1.0/token?grant_type=1";
var command_url = `https://openapi.tuyaus.com/v1.0/devices/${device_id}/commands`;
var command_urls = device_id.map(
  (key) => `https://openapi.tuyaus.com/v1.0/devices/${key}/commands`
);
var colour = {
  blue: { h: 240, s: 255, v: 255 },
  red: { h: 360, s: 255, v: 255 },
  green: { h: 120, s: 255, v: 100 },
};

function setColour(colors) {
  var timeStamp = getTime().toString();

  var token = retreiveAccessToken(clientId, clientSecret, timeStamp, url);
  var sign = calcSignWithToken(clientId, token, clientSecret, timeStamp);
  var headers = {
    client_id: clientId,
    access_token: token,
    t: timeStamp,
    sign: sign,
    sign_method: "HMAC-SHA256",
    "Content-Type": "application/json",
  };

  var options = {
    method: "POST",
    headers: headers,
    payload: JSON.stringify({
      commands: [
        { code: "switch_led", value: true },
        { code: "colour_data", value: colors },
      ],
    }),
  };
  // Logger.log(`access_token: ${token}`);
  // Logger.log(`sign :${sign}`);
  // Logger.log(`timestamp:${timeStamp}`);
  res = command_urls.map((key) => UrlFetchApp.fetch(key, options));
  Logger.log(res);
}

function retreiveAccessToken(clientId, clientSecret, timeStamp, url) {
  var easy_sign = calcSign(clientId, clientSecret, timeStamp);
  var headers = {
    client_id: clientId,
    sign: easy_sign,
    t: timeStamp,
    sign_method: "HMAC-SHA256",
    // Authorization: `Bearer $clientSecret`,
  };

  var options = {
    method: "GET",
    headers: headers,
    payload: {},
  };

  res = UrlFetchApp.fetch(url, options);
  return JSON.parse(res).result.access_token;
}

function getTime() {
  var now = new Date().getTime();
  return now;
}

function calcSign(clientId, clientSecret, timeStamp) {
  var str = clientId + timeStamp;
  var hash = Utilities.computeHmacSha256Signature(str, clientSecret);
  var signature = hash.reduce(function (str, chr) {
    chr = (chr < 0 ? chr + 256 : chr).toString(16);
    return str + (chr.length == 1 ? "0" : "") + chr;
  }, "");
  return signature.toUpperCase();
}

function calcSignWithToken(clientId, accessToken, clientSecret, timeStamp) {
  var str = clientId + accessToken + timeStamp;
  var hash = Utilities.computeHmacSha256Signature(str, clientSecret);
  var signature = hash.reduce(function (str, chr) {
    chr = (chr < 0 ? chr + 256 : chr).toString(16);
    return str + (chr.length == 1 ? "0" : "") + chr;
  }, "");
  return signature.toUpperCase();
}

ログインにめっちゃ苦労したけどなんとか出来た。よかったよかった。
iot.tuya.comのドキュメントの中にPOSTMANの使い方のなかにSHA256形式で暗号化してログインするというスクリプトが合ったのでそれをGASに合わせて書き換えるのが苦労した。

お風呂に温度異状があった場合にスマートライトの色を変える。

前回まででGASで異状検知した。

 

yadotech.hateblo.jp

 次はセルが更新された場合に電球の色を変える。

 

つかったのはこちら。

 

 大体いっこ1,500円くらい

 

あとはこれらをiftttでつなぐ。

 

IFTTTのつなぎ方は

SpreadsheetとSmartLife(スマートLEDのアプリ)をIFTTTに登録し、

 

Sheetsが更新されたらSmart Lifeで色を変えるというアクションを作る。

今回は3つの場合(熱い・冷たい・普通)で赤・青・緑に変更されるようにした。

 

f:id:devilmakelie:20200416173002p:plain

 

最後にGASをトリガー登録(時間主導)で10分ごとに登録する。

 

おしまい。

 

本日作ったばかりなので制限等はよくわからないが、そこそこいけるのではないかと考えている。

 

 

GASでおんどとりのAPIを叩く②

yadotech.hateblo.jp

ここから次は異状があったときに特定のセルを更新するまで

//環境に応じて書き換えるものはapi_key , login_id , password , 温度のところ(danshi , joshiのところ)です。
//

//温度を配列で返す関数
function temps(){  
  // api_key login_id password は書き直して下さい。
  const url = "https://api.webstorage.jp/v1/devices/current"
  const api_key = ""
  const login_id =""
  const password = ""
  const furo_temp = () => {
    var paylord = {'api-key':api_key,"login-id":login_id,'login-pass':password}
    var headers = {
      "X-HTTP-Method-Override":'GET',
      "Content-Type" : "application/json",}
    var options = {
     "method" : "post",   
     "payload" : JSON.stringify(paylord),
     "headers" : headers,
     "muteHttpExceptions":true
    }
    
    return UrlFetchApp.fetch(url,options);
  
  }
  return JSON.parse(furo_temp())
  
}

//ここまで関数

//ここから本文

//温度のJSONを取得する
var tmprs = temps()

//デバッグ用 女子風呂の温度
//Logger.log("女子:" + tmprs["devices"][1]["channel"][0].value)

//男子風呂の温度 環境に応じて切り替えて下さい
var danshi = tmprs["devices"][2]["channel"][0].value

//女子風呂の温度 環境に応じて切り替えて下さい
var joshi = tmprs["devices"][1]["channel"][0].value

var nowtime = new Date()
var status 
var sht = SpreadsheetApp.getActiveSheet()

if (Math.max(danshi,joshi)>44) {
  Logger.log("熱い")
//デバッグ用  sht.getRange("B1").setValue(nowtime)
  status = "hot"
}

if (Math.min(danshi,joshi)<38){
  Logger.log("冷たい")
//デバッグ用  sht.getRange("B3").setValue(nowtime)
  status = "cold" 
}

if (Math.min(danshi,joshi)<38 && Math.max(danshi,joshi)>44){
  Logger.log("なんか変")
  status = "somethingwrong"
}

//最後のswitch文
switch(status){
  case "hot":
    sht.getRange("D5").setValue(nowtime)
    break
  case "cold":
    sht.getRange("F5").setValue(nowtime)
    break
  case "somethingwrong":  
    sht.getRange("E5").setValue(nowtime)
    break
  default:
    sht.getRange("G5").setValue(nowtime)
    break    
  
    
}

GASでおんどとりWeb Storage APIを利用する。

Python版はこちら

yadotech.hateblo.jp


こんどはGASでおんどとりWEB STORAGE APIを利用してみた。

function temps(){  
  const url = "https://api.webstorage.jp/v1/devices/current"
  const api_key = "【API_KEY】"
  const login_id ="【ID】"
  const password = "【PASSWORD】"
  const furo_temp = () => {
    var paylord = {'api-key':api_key,"login-id":login_id,'login-pass':password}
    var headers = {
      "X-HTTP-Method-Override":'GET',
      "Content-Type" : "application/json",}
    var options = {
     "method" : "post",   
     "payload" : JSON.stringify(paylord),
     "headers" : headers,
     "muteHttpExceptions":true
    }
    
    return UrlFetchApp.fetch(url,options);
  
  }
  return JSON.parse(furo_temp())
  
}

Logger.log(temps())

後はお好きにすると良いと思います。

家で一番簡単にSpotifyをブロードキャストする方法

f:id:devilmakelie:20200126201034p:plain

 

以前はChromecast Audioという物があったのですが、現在は販売停止になっていて結構高くなっちゃってたので。

 

必要なもの

1.Chromecast (5,000円くらい)

store.google.com

2.HDMI分離器 (2,500円くらい)

 

 

この2個があれば後はGoogle Homeでオーディオグループを作成するだけ。

 

意外と簡単に行けたのでオススメ

 

 

AsteriskとOG410Xaをつなぐ

長かった・・・

 

結論からいうと

 

ID:10(内線番号)

Pass:なし

 

sip.confに書くだけっぽい。

これでOG410Xaがよしなにやってくれるみたいだった。
 

あとはExtensions.confに外線発信用のコンテクストを書くだけ、だと思う。



ということで

【OG410Xa側】

f:id:devilmakelie:20191202213002p:plain

ここはid:admin Pass:akisky-HARUSKY48

これで管理画面にログインし、

『電話設定』→『着信番号設定』を

f:id:devilmakelie:20191202213434p:plain

以上のようにする。

するとIP Phone2に着信が飛ぶようになる。

OG側の設定はこれくらい。あとはDHCP除外設定でAsteriskサーバーのIPアドレスを固定にしておくと後で何かと楽にはなる。

Asterisk側】

sip.conf

[general]
maxexpirey=3600
defaultexpirey=3600
context=default
bindport=5060
bindaddr=0.0.0.0
srvlookup=yes
disallow=all
allow=ulaw
allow=alaw
allow=gsm
language=ja
canreinvite = no
match_auth_username=yes

defaultexpiery=3600
maxexpiery=3600
register => 11:pass@192.168.1.1/800

[asterisk]
type=friend
username=1000
canreinvite=no
context=front
insecure=port,invite
host=【AsteriskのIPアドレス】
dtmfmode=auto
allowsubscribe=no

192.168.1.1は デフォルトゲートウェイIPアドレス

register =>11:pass@~/800

というところだがこれで内線電話としてAsteriskが登録される。800は登録されたOG410から着信があった場合の着信番号を記述する

extensions.confも普通に

[inandout]

exten => 800,1,Dial(SIP/100,30,tT)
exten => 800,n,Hangup()

exten => _0.,1,Set(CALLERID(num)=${MYNUMBER})
exten => _0.,n,Set(CALLERID(name)=${MYNUMBER})
exten => _0.,n,Dial(SIP/${EXTEN}@asterisk,120,T)

こんな感じでコンテキストをDefaultとかに追記するくらいでOK。

このままだと無限に外線が取れたり、2つ以上外線を取ると最初に取った分が保留状態になったりしているのでそこを今からなんとかする。