Androidのメモとか

ポキオの日記です。今日も遅延してない。

テレワーク用の椅子(5脚目)

ついに5脚目。

ポキオ カスケード Cascade Mountain Tech Compact High Back Aluminum Chair

テレワーク用の椅子の紆余曲折

いままで色々試してきました。

relativelayout.hatenablog.com

結局、最後に買った「ポンコタン ハイバックチェア」が一番しっくり来ていました。

なんですが、毎日座ってたせいで、ファブリックの縫い目がほつれ始めてきていました。

コストコ怪しいハイバックチェアが・・・

で、コストコでなにやらコスパの良さそうなハイバックチェアが売っていました。

ポキオ カスケード Cascade Mountain Tech Compact High Back Aluminum Chair

すぐにカートに入れちゃう癖やめたいところですが、なんと約3500円。

ポキオ カスケード Cascade Mountain Tech Compact High Back Aluminum Chair

きっと本国のメリケン人が乗っても壊れないんだろうなとか思うと、耐久性も期待できそうだったので早速購入。

Unboxingと組み立て

ポンコタンのハイバックチェアと同じように収納バッグに入ってて、非常にコンパクト。

ポキオ カスケード Cascade Mountain Tech Compact High Back Aluminum Chair

で、ひとまず開封。骨組みを組み立てるところまでは良かったが・・・。

ポキオ カスケード Cascade Mountain Tech Compact High Back Aluminum Chair

ファブリックの座面を骨組みに取り付けるのが本当に大変。未使用でファブリックが伸びてないのか、なかなか骨組みに入らず10分ほど格闘。最後はなんとか入りましたが。

ポキオ カスケード Cascade Mountain Tech Compact High Back Aluminum Chair

ちなみに、足はこんなタイプ。地面が砂地などでも潜り込まないような構造になっていますが、ポンコタンと異なり、この足は取り外しができないようです。

ポキオ カスケード Cascade Mountain Tech Compact High Back Aluminum Chair

で、完成。

座り心地は?

まず、ファーストインプレッションとして、

(ポンコタンのハイバックチェアと比べると…)

  • 背もたれは低めで、ハイバックというかミッドバック。
  • 左右方向のホールド感は低め。
  • 前後方向のホールド感は低めで、浅め。
  • 座面はちょっとだけ高め。
  • 大きめのヘッドレストがついてて快適。
  • 背もたれ上部に、左右方向に伸びる骨が入ってて安定感がある。

僕も割とお尻が大きい方ですが、それでも余裕があるので、ポンコタンより欧米寄りというのがわかります。とまぁ、色々差異はあるものの、なかなかの座り心地。耐久性の評価はこれからですが、すぐに壊れてもコストコなので返品しちゃえばいいしね。そう考えても3500円というのはコスパ高いですね。

ポキオ カスケード Cascade Mountain Tech Compact High Back Aluminum Chair

というわけで、カスケードマウンテンテックのハイバックチェアでした。次こそはHelinox買うん・・・だ・・・!

バチ抜けをNode-REDで地図に可視化する

つりはっく。

ポキオ Node-RED WorldMap バチ抜け

バチ抜けとは

釣り用語の一つです。

pokio-ringyo.hatenablog.com

pokio-ringyo.hatenablog.com

バチとはイソメやゴカイなどの環形動物のことを指し、バチ抜けとは春先の大潮の夜に海底に潜んでいるバチが一気に浮いてくる現象です。抜けたバチは種々の魚にとってはごちそうであって、バチを求めて魚が寄ってくるというわけです。バチ抜けは地域によって発生する時期がまちまちで、更に魚が寄ってくるかもわからない自然のイベントとなっているわけで、いつどのへんでバチ抜けが起こったのかを知りたいのは釣り人の性みたいなもの。

ポキオ輪業商会 横浜 メバリング シーバス プラッキング

今回は、Twitterで位置情報とともにつぶやかれている情報をもとに、バチ抜けなどの情報を地図上にマッピングしてみようと思います。

使うのはNode-RED

今回もNode-REDで実装していきます。フローはこんな感じ。

ポキオ Node-RED WorldMap バチ抜け

ポイントとなるノードはこちら。

Twitterノード

これでTwitter上の情報をほぼリアルタイムにスキャンして、指定したハッシュタグのツイートを引っ張ってきます。実際にツイートが見つかると、おそらくTwitter本家のTweet Objectの形式でデータが取得できます。

developer.twitter.com

ただ、仕様が複雑(笑)今回は、次のFunctionノードでテキトーに位置情報をパースします。

Functionノード

ここで、Twitterノードから取得したデータから位置情報をパースします。

if(msg.tweet && msg.tweet.place && msg.tweet.place.bounding_box && msg.tweet.place.bounding_box.coordinates){
    var longitude = 0;
    var latitude = 0;
    var array = msg.tweet.place.bounding_box.coordinates[0];
    var tweet = msg.payload.replace(/\r?\n/g,"");
    var link = 'https://twitter.com/' + msg.tweet.user.screen_name + '/status/' + msg.tweet.id_str;

    array.forEach(value => {
        longitude += value[0];
        latitude += value[1];
    });
    
    longitude /= array.length;
    latitude /= array.length;
    
    msg = {};
    msg.has_location = true;
    msg.payload = {
        "lat" : latitude,
        "lon" : longitude,
        "name" : tweet,
        "weblink" : link,
    };
}
return msg;

tweet.place.bounding_box.coordinates内の座標の平均値をとって、それを緯度経度として採用しています。後段の処理でCSVファイルに保存するため、Tweet本文は改行を削除してから保存しています。

CSVノード・Fileノード

前段の処理で、位置情報がパースできたTweetだけをCSVとして一旦保存しておきます。

WorldMapノード

今回の要。

flows.nodered.org

node-red-contrib-web-worldmapをインストールして、地図を表示できるようになります。フロー中にこのWorldMapノードがあると、特定のURLにアクセスすると地図が表示されるようになります。このノードに対して緯度経度などをくべると、地図上にピンが表示されるようになります。今回は、WorldMapにアクセスがあったときに発火するイベントを契機に、CSVを読み込み、そこに書かれた位置情報をすべてWorldMapにマッピングします。

これをつかって地図表示させてみました

こんな感じ。

ポキオ Node-RED WorldMap バチ抜け

まだまだTwitterの監視をし始めたばかりなのでピンはすくなめですが、ちゃんと可視化できています。

ちょっとずつピンが増えてくると楽しいですねぇ。

フローはこちら

[
    {
        "id": "add2a0f2.b28d2",
        "type": "twitter in",
        "z": "52e43921.021f08",
        "twitter": "",
        "tags": "バチ抜け,シーバス,#バチ抜け,#シーバス",
        "user": "false",
        "name": "バチ抜けツイート",
        "inputs": 0,
        "x": 130,
        "y": 300,
        "wires": [
            [
                "643d563.f2d9fa8",
                "1e92e179.29a17f"
            ]
        ]
    },
    {
        "id": "efe29703.79f498",
        "type": "comment",
        "z": "52e43921.021f08",
        "name": "ツイート監視",
        "info": "",
        "x": 110,
        "y": 260,
        "wires": []
    },
    {
        "id": "643d563.f2d9fa8",
        "type": "function",
        "z": "52e43921.021f08",
        "name": "位置情報パース",
        "func": "if(msg.tweet && msg.tweet.place && msg.tweet.place.bounding_box && msg.tweet.place.bounding_box.coordinates){\n    var longitude = 0;\n    var latitude = 0;\n    var array = msg.tweet.place.bounding_box.coordinates[0];\n    var tweet = msg.payload.replace(/\\r?\\n/g,\"\");\n    var link = 'https://twitter.com/' + msg.tweet.user.screen_name + '/status/' + msg.tweet.id_str;\n\n    array.forEach(value => {\n        longitude += value[0];\n        latitude += value[1];\n    });\n    \n    longitude /= array.length;\n    latitude /= array.length;\n    \n    msg = {};\n    msg.has_location = true;\n    msg.payload = {\n        \"lat\" : latitude,\n        \"lon\" : longitude,\n        \"name\" : tweet,\n        \"weblink\" : link,\n    };\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 340,
        "y": 300,
        "wires": [
            [
                "8649b0d9.a5f98"
            ]
        ]
    },
    {
        "id": "dddeedd9.5a74b",
        "type": "worldmap",
        "z": "52e43921.021f08",
        "name": "",
        "lat": "",
        "lon": "",
        "zoom": "",
        "layer": "",
        "cluster": "",
        "maxage": "",
        "usermenu": "show",
        "layers": "show",
        "panit": "false",
        "panlock": "false",
        "zoomlock": "false",
        "hiderightclick": "false",
        "coords": "none",
        "showgrid": "false",
        "allowFileDrop": "false",
        "path": "/worldmap",
        "x": 1060,
        "y": 460,
        "wires": []
    },
    {
        "id": "8649b0d9.a5f98",
        "type": "switch",
        "z": "52e43921.021f08",
        "name": "位置情報があるときだけ動作",
        "property": "has_location",
        "propertyType": "msg",
        "rules": [
            {
                "t": "true"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 580,
        "y": 300,
        "wires": [
            [
                "6d46063b.e4bce8"
            ]
        ]
    },
    {
        "id": "433fb432.0e49fc",
        "type": "function",
        "z": "52e43921.021f08",
        "name": "ズーム",
        "func": "msg.payload = {\n    command : {\n        lat : msg.payload.lat,\n        lon : msg.payload.lon,\n        zoom : 6,\n    }\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 930,
        "y": 480,
        "wires": [
            [
                "dddeedd9.5a74b"
            ]
        ]
    },
    {
        "id": "75d4e561.cf315c",
        "type": "worldmap in",
        "z": "52e43921.021f08",
        "name": "",
        "path": "/worldmap",
        "events": "all",
        "x": 100,
        "y": 460,
        "wires": [
            [
                "493cf6af.c9d1d8"
            ]
        ]
    },
    {
        "id": "493cf6af.c9d1d8",
        "type": "switch",
        "z": "52e43921.021f08",
        "name": "",
        "property": "payload.action",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "connected",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 250,
        "y": 460,
        "wires": [
            [
                "6381668a.b712c8"
            ]
        ]
    },
    {
        "id": "6d46063b.e4bce8",
        "type": "csv",
        "z": "52e43921.021f08",
        "name": "CSVに変換",
        "sep": ",",
        "hdrin": "",
        "hdrout": "",
        "multi": "one",
        "ret": "\\n",
        "temp": "lat,lon,name,weblink",
        "skip": "0",
        "strings": false,
        "x": 810,
        "y": 300,
        "wires": [
            [
                "96084250.d8c06",
                "23921cd8.841d44"
            ]
        ]
    },
    {
        "id": "96084250.d8c06",
        "type": "file",
        "z": "52e43921.021f08",
        "name": "history.csvに保存",
        "filename": "history.csv",
        "appendNewline": true,
        "createDir": false,
        "overwriteFile": "false",
        "encoding": "none",
        "x": 1010,
        "y": 300,
        "wires": [
            []
        ]
    },
    {
        "id": "23921cd8.841d44",
        "type": "debug",
        "z": "52e43921.021f08",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 970,
        "y": 340,
        "wires": []
    },
    {
        "id": "3b137fe3.26fa",
        "type": "csv",
        "z": "52e43921.021f08",
        "name": "",
        "sep": ",",
        "hdrin": "",
        "hdrout": "",
        "multi": "one",
        "ret": "\\n",
        "temp": "lat,lon,name,weblink",
        "skip": "0",
        "strings": true,
        "x": 630,
        "y": 460,
        "wires": [
            [
                "5786ae6a.d8e1"
            ]
        ]
    },
    {
        "id": "6381668a.b712c8",
        "type": "file in",
        "z": "52e43921.021f08",
        "name": "history.csvを読み込み",
        "filename": "history.csv",
        "format": "utf8",
        "chunk": false,
        "sendError": false,
        "encoding": "none",
        "x": 440,
        "y": 460,
        "wires": [
            [
                "3b137fe3.26fa"
            ]
        ]
    },
    {
        "id": "5786ae6a.d8e1",
        "type": "function",
        "z": "52e43921.021f08",
        "name": "weblink作成",
        "func": "const weblink = {\n    \"name\" : \"Twitter\",\n    \"url\" : msg.payload.weblink,\n    \"target\":\"_new\"\n}\n\nmsg.payload.weblink = weblink;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 790,
        "y": 460,
        "wires": [
            [
                "dddeedd9.5a74b",
                "433fb432.0e49fc"
            ]
        ]
    },
    {
        "id": "cddaa0e7.caea7",
        "type": "comment",
        "z": "52e43921.021f08",
        "name": "Mapにアクセスがあったとき",
        "info": "",
        "x": 160,
        "y": 420,
        "wires": []
    },
    {
        "id": "1e92e179.29a17f",
        "type": "debug",
        "z": "52e43921.021f08",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 310,
        "y": 340,
        "wires": []
    }
]

Node-REDをつかってGoogle Home Miniに時報を喋らせる

テレワークに便利。

ポキオ Google Home Mini 時報 Node-RED

tl;dr

  • Google Homeの「ルーティーン」を使ってもできる
  • 今回はNode-REDから時報を喋らせる
  • 定期的にタスクを実行して、喋らせたい文字列をGoogle Home MiniにCastするだけ

テレワークのタイムマネジメント

いうほどできてないんですが。ついうっかりミーティングの存在を忘れたりしがちなので、以前から1時間おきにGoogle Home Miniに時報を喋らせてました。

support.google.com

ルーティーンという機能をつかって、設定した時間に「OK, google. 今何時?」という問いを内部的に投げて、その答えをGoogle Home Miniから発話させることで、時報として活用していました。ただ、最近設定した時間の±1分くらいに発火する謎の病にかかってしまい、代替手段を探していました。で、今回はその方法としてNode-REDからGoogle Home Miniに対して時報を喋らせてみようと思います。

フローは至ってシンプル

最初にフローから。

ポキオ Google Home Mini 時報 Node-RED

こんな感じ。

ポキオ Google Home Mini 時報 Node-RED

まずはInjectionノードで定期実行をトリガー。「おいおい、真夜中に発火させてどうした?」みたいなこと思うかもしれませんが、Node-REDが動作しているRaspberry PiタイムゾーンがUKのままなので、運用でカバーしています・・・(笑)良い子は真似しないでね。

次のFunctionノードで発話させるメッセージを作成しています。こちらでもタイムゾーンをゴニョゴニョしてます。

const date = new Date(Date.now() + ((new Date().getTimezoneOffset() + (9 * 60)) * 60 * 1000));
msg.message = "現在の時刻は、だいたい" + date.getHours() + "時です。";
return msg;

そして、実際の発話はnode-red-contrib-castノードで実行しています。

flows.nodered.org

文字通り、Castを行うノードですが、対象のIPアドレスGoogle Home MiniのIPアドレスにすると、msg.messageのStringを発話してくれます。

実際のフローはこちら

[
    {
        "id": "3e94927e.7c6d7e",
        "type": "cast-to-client",
        "z": "36b47ac9.340b66",
        "name": "",
        "url": "",
        "contentType": "",
        "message": "",
        "language": "ja",
        "ip": "192.168.1.31",
        "port": "",
        "volume": "50",
        "x": 630,
        "y": 120,
        "wires": [
            []
        ]
    },
    {
        "id": "fdae59a3.98caa8",
        "type": "inject",
        "z": "36b47ac9.340b66",
        "name": "22:00-00:00",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "",
        "crontab": "0 22-23 * * 1,2,3,4,5",
        "once": false,
        "onceDelay": 0.1,
        "x": 140,
        "y": 60,
        "wires": [
            [
                "88c5f7d4.a36758",
                "b569a844.e50c58"
            ]
        ]
    },
    {
        "id": "88c5f7d4.a36758",
        "type": "debug",
        "z": "36b47ac9.340b66",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 370,
        "y": 60,
        "wires": []
    },
    {
        "id": "b569a844.e50c58",
        "type": "function",
        "z": "36b47ac9.340b66",
        "name": "メッセージ作成",
        "func": "const date = new Date(Date.now() + ((new Date().getTimezoneOffset() + (9 * 60)) * 60 * 1000));\nmsg.message = \"現在の時刻は、だいたい\" + date.getHours() + \"時です。\";\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 380,
        "y": 120,
        "wires": [
            [
                "3e94927e.7c6d7e"
            ]
        ]
    },
    {
        "id": "a93920ed.ddbc3",
        "type": "inject",
        "z": "36b47ac9.340b66",
        "name": "00:00-10:00",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "",
        "crontab": "0 0-9 * * 1,2,3,4,5",
        "once": false,
        "onceDelay": 0.1,
        "x": 140,
        "y": 120,
        "wires": [
            [
                "88c5f7d4.a36758",
                "b569a844.e50c58"
            ]
        ]
    }
]

カードが不正利用されました

流石にビビった。

ポキオ LINE PAY カード 不正利用 Amazon 500円

きっかけ

ある日、LINE PAYカード(JCBプリペイドカード)での利用通知がアプリに届いたんですが。

ポキオ LINE PAY カード 不正利用 Amazon 500円

「Amazon 500円」

いや、何も買った覚えはないし、Amazonは別のカードを紐付けているので、そもそもLINE PAYカードにAmazonから請求が来るのはおかしいと思い、とりあえず不正利用の可能性が高まりました。

まずはLINE PAYカードのカスタマーサービスに連絡

すると、こんな返信が。

【1】請求内容の確認について

恐れ入りますが、Amazonからの請求内容については、注文履歴をご確認ください。

なお250円、500円、4,900円の請求の場合、Amazonプライム会費の可能性があります。

ほうほう。少なくとも自分のアカウントを確認しても、請求先は違うので、これはなさそう。

【2】問題が解決できない場合

Amazonカスタマーサービスにご相談いただいた上で、覚えがないまたは、購入内容が確認できない場合は、弊社にて対象取引の取消手続きを承ることが可能です。​

弊社での取消手続きには、事前にお客さま自身で以下2点をご対応いただく必要があります。

・請求が発生したLINE Pay カードの解約操作

・最寄りの警察署へ被害内容の相談

どうやらLINE PAYカード側でトランザクションのキャンセルを行うには、いろいろ手順を踏まないとダメそうということがわかりました。結構面倒なんですね。

次にAmazonカスタマーサービスに連絡

出来事をAmazonカスタマーサービスに連絡したところ、その場で私のアカウントで発生した請求ではないと言うことが判明。引き続き、専門のチームで調査を進めた結果、翌日にAmazonから連絡があり、

  • 私以外のアカウントで利用されたことが確認できた
  • 私が承認した決済でないことから、そのアカウントに対して適正な対処をした(BANってこと?)
  • 500円に関しては返金予定

とのことでした。Amazonのフットワークの軽さに感動。

ということで、LINE PAYカードを解約することなく、返金が行われることになり、一旦解決。

なぜ不正利用されてしまったのか問題

起こってしまったことはしょうがないとして、なぜ不正利用されてしまったのかは気になるところ。

スキミングや物理的にカード番号・CVVが漏れた

多分ないはず。リアル店舗でLINE PAYカードを使うことはまずないし、カードを持ち歩こともないので、この線は可能性が低いと思っている。

ネットで利用した際にカード番号・CVVが漏れた

ここ数年の利用を遡ってみると、ほとんどがLINEアプリ上でのLINE PAYの決済で、JCBプリペイドカードとしての利用はあまりありませんでした。ただ、ちょっと怪しいのが、

  • 某自転車通販サイト(台湾)
  • 某総合ECサイト(中国)

このあたりは、Paypalが使えなかったため、LINE PAYカードで決済をしていました。あまり信じたくないですが、こういうところから漏れたんですかねぇ…。

総当り攻撃でカード番号・CVVが漏れた

そうでないと願っています。

不正利用されることは防げないという前提で対策をする

まぁ、犯人探しは想像の域を出ないので、今後はちゃんと対策をしていきたいです。

不要なカードは停止

クレジットカード・プリペイドカードは便利なんですが、それはセキュリティホールでもあるということがわかったので、使わないものは停止をしようと思います。LINE PAYカードなどは、アプリから一時的にカードを停止したりできるので、そういう機能も使っていこうと思います。

利用時に通知を受けられるようにする

今回も、問題発覚の要因になったのは利用通知でした。メインのカードも通知が飛ぶように設定をしました。

ポキオ LINE PAY カード 不正利用 Amazon 500円

www.smbc-card.com

カードの補償内容を確認

不正利用時にカード会社がどのくらい補償してくれるかは、会社によってまちまちです。LINE PAYカードの場合は、

(3) 1事故(一事由または同一原因による一連の事由により発生した損害をいいます。)あたりの補償限度額は、原則、10万円とします。ただし、前二号で定める補償対象となる損害の額が10万円を超過する場合は、利用者のご利用状況や警察当局による捜査結果等を踏まえ、補償限度額の引き上げを個別に検討します。

https://terms2.line.me/linepay_JP_Money_new_TermsofUse?lang=ja

となっており、10万円くらいは補償の対象っぽいです。カードによっては補償がなかったりすることもあるので、確認が必要ですね。

ヤバそうなサイトは捨てカードで決済

今回も、Paypalが使えない怪しげなサイトだったのでプリペイドカードで決済をしましたが、今後もそういうサイトを利用する際はメインのカードではなく、利用できる額が少額になっているプリペイドカードでの決済が安心かもしれませんね。

というわけで

不正利用なんて他人事だとおもってましたが、まさか自分の身にも降りかかると思ってもいなかったです。今後も気をつけて使っていきたい所存。

M5Stackに潮汐を表示させてみる

大潮でも釣れないときは釣れないんですけどね。

ポキオ M5Stack 潮汐

前回は潮汐情報のWebサービスを見つけました

全国各地のポイントの潮汐情報を日付を指定して取得できるすごい子でした。

relativelayout.hatenablog.com

今回は、これを使ってM5Stackに潮汐情報(とりあえず、大潮、中潮、・・・など)を表示させてみようと思います。

環境と実装

  • 実装環境:UIFlow(Betaのほう、v1.7.2)
  • バイス:M5Stack Basic

ここで、UIFlowはBetaのほうを使っているのがミソです。Betaの方だとNTPが使えるため、こちらを使用しています。(それに合わせて、M5Stackのファームウェアも更新しています)

ポキオ M5Stack 潮汐

こんな感じでブロックを組み立てていきます。やっていることとしては、

  • Wi-Fi接続
  • ntptimeの初期化
  • 定期的に潮汐情報ページにアクセス(日付指定にntptimeで取得した現在日付を使う)
  • 潮汐情報に応じて予め準備した画像を表示

このような処理です。

画像は予め準備

macKeynoteとかで、大潮用、中潮用、・・・の320x240な画像を予め準備して、M5Stackに流し込んでおきます。

ポキオ M5Stack 潮汐

ローディング画面用も一応作成。流し込んだ画像をコードから参照して表示させています。

早速動作確認

うーん、今日は中潮!ちゃんと動いてそうですね!

ポキオ M5Stack 潮汐

こういうガジェットを作ったからと言って、釣果が良くなるかは別の話なので、あしからず。

MicroPythonのコードはこちら

from m5stack import *
from m5ui import *
from uiflow import *
import wifiCfg
import ntptime
import urequests
import time

setScreenColor(0x222222)


url = None

wifiCfg.doConnect('*****', '*****')
image0 = M5Img(0, 0, "res/loading.jpg", True)




while not (wifiCfg.wlan_sta.isconnected()):
  pass
ntp = ntptime.client(host='jp.pool.ntp.org', timezone=9)
while True:
  image0.changeImg("res/loading.jpg")
  url = 'http://fishing-community.appspot.com/tidexml/index?portid=112&year=YYYY&month=MM&day=DD'
  url = url.replace('YYYY', str((ntp.year())))
  url = url.replace('MM', str((ntp.month())))
  url = url.replace('DD', str((ntp.day())))
  try:
    req = urequests.request(method='GET', url=url)
    if 0 < (req.text).count('大潮'):
      image0.changeImg("res/ooshio.jpg")
    if 0 < (req.text).count('中潮'):
      image0.changeImg("res/nakashio.jpg")
    if 0 < (req.text).count('小潮'):
      image0.changeImg("res/koshio.jpg")
    if 0 < (req.text).count('若潮'):
      image0.changeImg("res/wakashio.jpg")
    if 0 < (req.text).count('長潮'):
      image0.changeImg("res/nagashio.jpg")
  except:
    pass
  wait(3600)
  wait_ms(2)

macOS Big SurにESP8266開発環境を構築する(Arduino IDE)

今回もハマったお。

ポキオ ESP8266 Arduino macOS Big Sur

Big Sur環境に構築

Big Surをクリーンインストールしたのはいいのですが。

relativelayout.hatenablog.com

Arduino開発環境などが綺麗サッパリなくなってしまったので、いちから構築してみました。特に、よくプロトタイピングで使うESP8266が動くようにしてみました。

ESPr Developer(ピンソケット実装済)

ESPr Developer(ピンソケット実装済)

  • メディア: おもちゃ&ホビー

まずはArduino IDEをインストール

なにはともあれ。

ポキオ ESP8266 Arduino macOS Big Sur

www.arduino.cc

公式HPからmacOS向けのバイナリをダウンロード。そのままApplicationフォルダにどーん。

ポキオ ESP8266 Arduino macOS Big Sur

とりあえず起動はOKそうです。

ESP8266が開発できるようにする

Arduino core for ESP8266 WiFi chipを導入します。

github.com

設定画面のAdditional Boards Manager URLshttps://arduino.esp8266.com/stable/package_esp8266com_index.jsonを追加します。

ポキオ ESP8266 Arduino macOS Big Sur

するとBoard ManagerにESP8266が現れるので、インストールしちゃいます。

ポキオ ESP8266 Arduino macOS Big Sur

ESP8266をmacにつなぐと、認識もされるようです。

ポキオ ESP8266 Arduino macOS Big Sur

ビルドができない・・・?

と、ここまでは良かったんですが。いざコンパイルをしようとすると失敗してしまいます。

pyserial or esptool directories not found next to this upload.py tool.

An error occurred while uploading the sketch

どうやら、ライブラリをロードする部分で失敗しているようです。

mag.switch-science.com

forum.arduino.cc

~/Library/Arduino15/packages/esp8266/hardware/esp8266/2.7.4/tools/pyserial/serial/tools/list_ports_osx.pyの一部を書き換えます。

ポキオ ESP8266 Arduino macOS Big Sur

29行目・30行目を下記のように書き換えます。

iokit = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/IOKit.framework/IOKit')
cf = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation')

これで書き込めるようになりました!

ポキオ ESP8266 Arduino macOS Big Sur

釣りをハックする

釣りです。

ポキオ 釣り IoT ハック

空前の釣りブーム

はい、最近釣りをしてばっかりです。

コロナ禍で勉強会が中止になったりオンライン開催でなんとなくテンションが上がらない一方で、地元で過ごすことが多くなったので自転車乗ったり釣りに行ったりしてたわけで。プライベートでコーディングすることからちょっと離れてしまったのは確かですが、新たな課題が見つかったのも事実です。

釣りはハックする余地がある?

自転車もそうですが、釣りも割と科学的な側面を持っていて、潮汐・水温・気圧などの気象条件や、キャスティングやアクションなどの釣り方、明暗や海水の濁り具合など、いろいろなファクターの重ね合わせで釣果が変わるといっても過言ではないと思っています。

ポキオ 釣り IoT ハック

一気に全部のファクターに手をつけちゃうと大変そうなので(笑)、まずはかんたんなところから手をつけていこうかと思います。

まずは潮汐

潮の満ち引きはもちろん重要なファクターの一つ、まずはここから着手します。潮汐データを取得できるWebAPIがあるかなと調べてみると、結構ありますねぇ。

fishing-community.appspot.com

www.data.jma.go.jp

大多数が有料なWebAPIのなかで、上記2つは無料でそこそこ使えそうな情報源になりそうでした。例えばfishstarのAPIだと、任意の日付・場所の潮汐情報が取得できます。

2021/01/21の横浜の根岸の潮汐データの場合、下記のようなURLにアクセスすると・・・

http://fishing-community.appspot.com/tidexml/index?portid=112&year=2021&month=01&day=21

<?xml version="1.0" encoding="UTF-8"?>
<tideinfo>
   <port-id>112</port-id>
   <port-name>根岸</port-name>
   <latitude1>35°24'</latitude1>
   <longitude1>139°38'</longitude1>
   <latitude2>35.400000</latitude2>
   <longitude2>139.633333</longitude2>
   <year>2021</year>
   <month>1</month>
   <day>21</day>
   <youbi></youbi>
   <sunrise-time>06:48</sunrise-time>
   <sunset-time>16:59</sunset-time>
   <moonrise-time>11:26</moonrise-time>
   <moonset-time>--:--</moonset-time>
   <tide-name>小潮</tide-name>
   <tidedetails>
      <tide-time>03:28</tide-time>
      <tide-level>74</tide-level>
   </tidedetails>
   <tidedetails>
      <tide-time>10:06</tide-time>
      <tide-level>148</tide-level>
   </tidedetails>
   <tidedetails>
      <tide-time>17:11</tide-time>
      <tide-level>66</tide-level>
   </tidedetails>
   <tidedetails>
      <tide-time>23:14</tide-time>
      <tide-level>111</tide-level>
   </tidedetails>
   <tidedetails>
      <tide-time />
      <tide-level />
   </tidedetails>
   <tidedetails>
      <tide-time />
      <tide-level />
   </tidedetails>
   <tidedetails>
      <tide-time />
      <tide-level />
   </tidedetails>
   <tidedetails>
      <tide-time />
      <tide-level />
   </tidedetails>
</tideinfo>

こんな感じでいろいろなデータが取得できました。これを使えば様々な用途に活用できそうですねぇ。

「Androidのメモとか」は、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、Amazonアソシエイト・プログラムの参加者です。

このブログは個人的なメモ書きであったり、考えを書く場所であります。執筆者の所属する団体や企業のコメントや意向とは無関係であります。また、このブログは必ずしも正しいことが書かれているとは限らず、誤字脱字や意図せず誤った情報を載せる場合がありえます。それが原因で読者が不利益を被ったとしても、執筆者はいかなる責任も負いません。ありがとうございます。