さぼてんメモ

さぼてんのメモです。メモなので推敲粗め。趣味:工作やハンドメイド 勉強中:回路っぽいことやプログラミング

ミスミメンテbotにカウントダウンを実装した

カウントダウン機能をつけたくなった

ミスミメンテbotは メンテナンスが予告されている間毎日ツイートする仕様。

毎日まったく同じツイートをするのはつまらない。 そこで、カウントダウン機能をつけることにした。

実装

以下のようなカウントダウンの関数を作った。

いままでのプログラムではツイートしかしなかった為、 ミスミサイトから取得した日時を数字に変換せず文字列として扱っていた。 また、開始終了の日時をまとめて使いやすくする為、配列に格納している。

そこで、ひとまず文字列の配列として日時を受け取り、関数内で数字への変換機能を実装することにした。

# countdownを文字列で返す
# 入力は文字列の配列
def count_down(date, time):

メンテ日時の文字列を数字に変換

先述したように、今までは日時を文字列として扱っていた。

今回は残り日時の計算に使いたいので、数字に変換する。

# 取得日時を切り出してintにする
str = re.sub(r'\D', ' ', date[0])
sdate = str.split()
smonth = int(sdate[0]) # 月
sday = int(sdate[1]) # 日
str = re.sub(r'\D', ' ', time[0])
stime = str.split()
shour = int(stime[0]) # 時

現在日時の取得

現在日時はpythonの機能で取得できる。

気をつけなければいけないのはタイムゾーン

ミスミサイトの表示はJST。 筆者は日本に住んでいて、JST設定のPCを使っている。 そのため、ローカルで日時差分をとると何も考えなくても問題なく動く。

しかし、定期実行に使っているherokuはデフォルトでJSTではない為、 明示的にタイムゾーンJSTに指定する必要がある。

# 現在日時
# タイムゾーンの生成
JST = timezone(timedelta(hours=+9), 'JST')
# JSTで現在時刻
time_info=datetime.now(JST)
# time_info=datetime.today()
print('time_info:{}'.format(time_info))
year_now = time_info.year

メンテ日時を現在日時と同じ形式に整える

ところで、ミスミサイトのメンテ日時案内には年が表示されたりされなかったりする。 また、ツイート本文に年をわざわざ書く必要も感じない。

このため、スクレイピングでは年情報を取得していない。

しかし、 datetimeオブジェクトを使いたいので、 メンテ日時にも年情報が必要となる。

datetime --- 基本的な日付型および時間型 — Python 3.8.1 ドキュメント

メンテナンスが年末年始に行われることはないだろうと考え、 現在の年=メンテ時の年 と指定する。

前章で用意した、

year_now = time_info.year

を利用する。

# 開始日時
# メンテは年をまたがないと仮定
# time_start = datetime(year_now,1,2,3)
time_start = datetime(year_now,smonth,sday,shour, tzinfo=JST)
print('time_start:{}'.format(time_start))

フォーマッティングして文字列として返す

引き算で差分を計算。

秒で出るので時間に変換。

フォーマットを使うときれいな表示になる。

# 差分
time_diff = time_start-time_info

# 文字列を返す
cd_s = "{0}日と{1}時間".format(time_diff.days, time_diff.seconds // 3600)

作成したコード

参考文献

django - How do I convert datetime.timedelta to minutes, hours in Python? - Stack Overflow

Mint60の一体型ケースを自作した

ずいぶん前(2019GW)につくったものだけどやっと記事化.

対象キーボード

自作キーボードキットのMint60

eucalyn.shop

eucalyn.hatenadiary.jp

製作背景

cactus-k.hatenablog.com

キーボードのケースを作ったものの,以下のような点がつかいにくいことに気づいた.

  • キーボードよりひとまわりかさばってしまう
  • 使用中の箱が置き場所を取るので少々邪魔
  • 緩衝材に使ったマットが重い

これを改善する為,一体型の専用ケースを作ることにした.

つくったもの

f:id:cactus_k:20190824114959j:plain

使い方

  1. 持ちて近くのスナップをはずす
  2. 開く
  3. ベルトを抜いてケース部分を外せば使用可能

f:id:cactus_k:20190824115041j:plain f:id:cactus_k:20190824115239j:plain

材料・道具

  • 合成皮革(「マドンナ」赤・茶)
  • ベルト用金具
  • スナップボタン(ベルト金具と合わせてアンティークゴールドのものを購入)
  • 接着剤(コニシ ボンド Gクリヤー(箱) 20ml #14321 コニシ(Konishi) Amazon CAPTCHA )
  • 3Dプリンタ(PLAを積層できるタイプ)
  • ミシン

作り方

骨格のモデリング

f:id:cactus_k:20190824115435p:plain

骨格作成

f:id:cactus_k:20190824115555j:plain

装飾作成

f:id:cactus_k:20190824115522j:plain

布は接着剤で貼っている.

持ちて部分はミシンで縫い付けている.

角の茶色の布は接着剤で貼った後でミシンで縫うことで雰囲気が出る.

感想

Mint60の付属ねじを無理やりねじこんで固定したので固定があやしい. インサートナットを使用してちゃんと固定できるようにしたい.

布は革と違って端面が白くで絵にならないのできれいにつくるのが難しい.

(おまけ)天下一わいわいキーボード行ってきました

これ持って行ってきた. いろんな切り口で製作・改造しているものをたくさん見られたので良かった.

キーキャップ自作をしている方がたくさんいて楽しそうだったのでやってみたい.

xpathを学んでミスミメンテbotのメンテ情報取得を改善した

困っていたこと

ミスミメンテbotが時々うまく動かないバグに困っていた.

動かなくなる状況を確認してみると, ミスミサイトでトラブルが発生し,ページ上部に緊急お知らせが出されるときに動かなくなる.

緊急お知らせがでてきた様子は こんな感じ.

f:id:cactus_k:20190824111613j:plain

赤枠の欄が緊急時のみ出現する. 赤枠のせいでレイアウトがずれるのが原因らしい.

もともとの取得方法

レイアウトがずれただけで動かなくなってしまうのは以下のようなやり方をしていたのが原因.

f:id:cactus_k:20190824111631p:plain

もともとは以下のようにメンテ情報を取得していた.

  1. chromeデベロッパーツールでメンテお知らせ欄(青枠)のpathを探し出す
  2. 右クリックで出てくる画像赤枠の部分からxpathをコピー
  3. 青枠内の何番目にメンテ情報が記載されるか不明の為,青枠内を十分回数のforループで順番に取得
  4. "メンテナンス"という文字がある行の日時を取得してツイートに反映

このやり方だと,xpathは要素の位置の形式を使うことになる. 当然レイアウトがずれるとこの記述もかわるので正しく取得できないということになる.

実際のコードだと以下の行.

# メッセージを順番に取得
mescnt = 0
i = 1
for i in range(1,cnt):
    headings = html.xpath("string(/html/body/div[1]/div[3]/div[1]/div[1]/div/ul/li[" + str(i) + "])") 
    if [headings]!=['']:
        message += [headings]
        mescnt += 1

改善した

「attention--infoというクラスで囲まれているので 順序ではなくタグとclass名でXPath指定すると結構ロバストになるよ(要約)」

というアドバイスをもらったので調べました. (xpathあんまりわからずに使っていた...)

調べたこと

以下のページがとても分かりやすかった.

techblog.zozo.com

xpathではXML文章をツリー構造としてとらえていて, (開発者が書いていれば)class属性がラベルのようにくっついている.

で,そのラベルを使った指定もできるらしい.できないと存在意味ない気がするのでそれはそうだけどとても便利.

上のページを見ると,コンテンツの文字列で検索しての指定や,指定要素の兄弟要素(○○の行の一個上とかが取得できそう)という指定方法もあるらしい.

書いてみたコード

これを読んで改善したコードを最後に貼る.

attention--infoというclass属性を指定するやり方で書いてみた. ちなみに,緊急お知らせ欄(赤枠)の属性はattention--notice.

xpath側で"メンテナンス"で検索をかけるようにするとプログラムがとても短くなりそう. ただ,ミスミサイト内の予想外の場所に"メンテナンス"という文字列が現れる可能性があるので,青枠内を取得する方針は維持することにした.

# メッセージを順番に取得
mescnt = 0
i = 1
for i in range(1,cnt):
    # メンテが予告される青枠部分を指定して取得
    headings = html.xpath("string(//ul[@class='attention--info']/li[" + str(i) + "])") 
    if [headings]!=['']:
        message += [headings]
        mescnt += 1
# print(mescnt) # メッセージ数
print(message)

備考

貼っている画像はすべて MISUMI-VONA | ミスミの総合Webカタログスクリーンショット

3Dプリンタパーツへのインサートナット圧入で微妙に失敗したのを修復した

3Dプリンタパーツへのインサートナット圧入をやってみた

3Dプリンタパーツ(ここではABSやPLAのFDM式を想定)へめねじを切る簡単なやり方として,インサートナットをはんだごてを用いて圧入する方法がある.

適切な径と深さの下穴をモデリングして造形して,あとから入れるだけなので手軽.

今作っているものにめねじを切る必要があった為,ためしてみた.

 

今回使ったのはこれ↓(M3,長さ4mm).

ja.aliexpress.com

※下記サイトを参照すると 本来これは熱圧入するものではなさそうだが. コンパクトであるのと,試してみて問題がなかった為これを使った.

www.monotaro.com

発生した失敗

適当なサイズの止まり穴を造形し,圧入した.

実際にやってみるとこんな感じになった.

f:id:cactus_k:20190813020844j:plainf:id:cactus_k:20190813020840j:plain

めねじ部分に樹脂がつまっている.

止まり穴なので,つまりの除去が困難. 千枚通し等で掻き出す方法ではうまくとれなかった.

 

比較対象としてうまくいったものが以下.

f:id:cactus_k:20190813020848j:plain

原因として考えられること:

  1. 下穴の径・深さが適切でなく樹脂が逃げ場を失って上がってきた
  2. 使用したナットに対してはんだごての先端が長すぎ,溶けた樹脂はんだごてを介してがナットの内側に付着した

f:id:cactus_k:20190813020828j:plain

 

(本来下穴や使うはんだごてを試行錯誤したうえで本番パーツを作るべきという話ではあるのだが,) めねじのつまりさえなくせれば使えそうだった為,修復を試みた.

対処

用意するもの:

  • アクリサンデー
  • 予備のねじ(ねじが汚れるので組立時に使うものとは別に用意した方が良い)
  • 綿棒(なければティッシュとか)
  • (つまようじ)

やりかた:

  • ねじ穴にアクリサンデーを入れる
    • アクリサンデーに付属の針でめねじが浸る程度入れる
    • あふれてしまった場合は周りが溶けるので早めにふき取る
  • とれにくい樹脂の塊はこの段階でつまようじで除去する
  • 下の画像では見づらいのだが,この時点で目詰まりがわりと消える

f:id:cactus_k:20190813021520j:plain

  • 予備のねじを入れる
  • 止まり穴の内部がやわらかくなっているので,樹脂を押しのける感覚で完成時に入れたい深さまで入れる
  • アクリサンデーが溢れてくるので綿棒かティッシュで吸っておく

f:id:cactus_k:20190813020834j:plain

 

完成したねじ穴が以下.

f:id:cactus_k:20190813020852j:plain

アクリサンデーが蒸発するまで放置して完成.

補足

今回のパーツはABS製. たぶんPLAでも可能だが試していない.

アクリサンデーの正しくない使い方なので責任は負えません...

3Dプリンタパーツの接着や修復(線状に割れた,など)にアクリサンデーを使うときれいに仕上がるので,1本持っておくと便利(これが本来の用途).

ミスミメンテbotを改良した~pythonで直接ツイート~

前作ったこれを改良しました

cactus-k.hatenablog.com

  • 上記記事でiftttというサービスを利用して簡単なbotを作った
  • おかげ様でわりと見てもらってるぽい(うれしい)
  • 調整作業をしたり,意見をもらう中で改善点がたまってきたので改良することにした

今回作ったもの

メンテがあるときつぶやくbot twitter.com

メンテがないときつぶやくbot twitter.com

実際のツイート

前回からの改善点

  • メンテがあるときとないときのアカウントを分けた
    • ツイートのpush通知をONにして使ってもうるさくない(利用者にうれしい)
  • ツイート内容のカスタマイズが楽になった(私がうれしい)
    • プログラム上で直接ツイート内容を記述・投稿できるようにした
    • これに伴いツイート内容に渡せる引数の数の制限もなくなった

なぜわざわざ作り直したのか・今回の目標

  • 2019年3月から運用を続けた結果,以下のように改善点・不満点がたくさんでてきた.
    • ツイートの内容を細かくカスタマイズできない
      • iftttで提供されているツイートフォーマットに従うツイートしかできない
      • iftttのwebhookからツイートに渡せる引数は3つまで
    • メンテがあるときとないときでTwitterアカウントを分けたい
      • iftttアカウント1つに対し,Twitterアカウントは1つしか登録できない(はず)
      • つまり複数アカウントからツイートしたい場合同数のiftttアカウントを作る必要があり管理が面倒
    • botメンテが面倒
      • ツイートの種類数分,iftttのappletを独立に新規作成している
      • bot改修のたびにプログラムと機能数分のappletを矛盾なく変更するのが面倒

つまり今回やりたいこと:iftttを使わずに複数アカウントからツイートできるようにする

Step1. システムのしくみ

  • iftttを利用しないしくみに変えた.
  • 同時にメンテの有無によってアカウントを分けるように変更した.

以前のシステム

f:id:cactus_k:20190708171006p:plain
以前のしくみ

新しいシステム

f:id:cactus_k:20190708171019p:plain
新しいしくみ

Step2. プログラムからのツイート

Twitter appの作成とアクセストークンの取得

Consumer Key
Consumer Secret
Access Token
Accesss Token Secert

の4つの英数字列がアクセストークンで,これをあとで使う.

python3からのツイート

  • 前記事のpython3で書いたメンテ判定のプログラムを使いたい為,python3を利用する前提で作成.

    基本的なしくみ

    これ↓を参考にした.

qiita.com

上で紹介されているコードで使われているライブラリが↓.

requests-oauthlib.readthedocs.io

Requests-OAuthlib uses the Python Requests and OAuthlib libraries to provide an easy-to-use Python interface for building OAuth1 and OAuth2 clients.

というものらしく, pythonで画像付きツイートをしたい人はだいたいこれを使っていた.

複数アカウント対応

一つのコードから複数のアカウントを利用するので,アカウント切り替えがしやすいように整備.

アクセストークンの登録

入れ子にした辞書型を使うと便利. 以下のように別ファイルsecret_cactus.pyに記述.

twDict = {'mainte':{
    'consumer_key' : 'xxxxxxxxxxxxxxxx',
    'consumer_secret' : 'xxxxxxxxxxxxxxxx',
    'access_token_key' : 'xxxxxxxxxxxxxxxx',
    'access_token_secret' : 'xxxxxxxxxxxxxxxx'
    },
    'nomainte':{
    'consumer_key' : 'xxxxxxxxxxxxxxxx',
    'consumer_secret' : 'xxxxxxxxxxxxxxxx',
    'access_token_key' : 'xxxxxxxxxxxxxxxx',
    'access_token_secret' : 'xxxxxxxxxxxxxxxx'
    }
}

これを以下のように取り込む.

(別ファイルimportだけして直接右辺の形で使ってもよいのだが,長くなるので以下のようにした)

import secret_cactus
pw = {}
pw['mainte'] = secret_cactus.twDict['mainte']
pw['nomainte'] = secret_cactus.twDict['nomainte']
ツイート関数

先述の記事を参考にしてアカウント切り替えがしやすい関数を作成した.

以下のように添付画像pic,投稿文字列messageに加えアカウント名tw_acを引数にとる関数を作成.引数で指定したアカウントのトークンを辞書から探してきてOAuth認証する.

def tweet_with_pic(tw_ac, pic, message): # 文字列,文字列,文字列
    # OAuth認証 セッションを開始
    tweet_ac = OAuth1Session(pw[tw_ac]['consumer_key'], pw[tw_ac]['consumer_secret'], pw[tw_ac]['access_token_key'], pw[tw_ac]['access_token_secret'])

    # 画像投稿
    files = {"media" : open(pic, 'rb')}
    req_media = tweet_ac.post(url_media, files = files)

    # レスポンスを確認
    if req_media.status_code != 200:
        print ("画像アップデート失敗: %s", req_media.text)
        exit()

    # Media ID を取得
    media_id = json.loads(req_media.text)['media_id']
    print ("Media ID: %d" % media_id)

    # Media ID を付加してテキストを投稿
    params = {'status': message, "media_ids": [media_id]}
    req_media = tweet_ac.post(url_text, params = params)

    # 再びレスポンスを確認
    if req_media.status_code != 200:
        print ("テキストアップデート失敗: %s", req_text.text)
        exit()

    print ("OK")

プログラムの定期自動実行

ミスミメンテbotをつくった(簡易版) - さぼてんメモ

と同じくherokuを利用.

利用するライブラリが増えたら忘れずにrequirements.txtに書き足すことに注意.

Step3. できたコード全体

以前のプログラムをベースに作成したもの. メンテ予告メッセージ取得や状況に応じた投稿内容はほぼそのまま.

  • 本体
  • requirements.txt
django
gunicorn
django-heroku
lxml
requests
requests_oauthlib

参考文献

OAuthのイメージがわかりやすかった記事 https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be

AndroidStdioの教材を探して勉強してみる

アプリを作りたくなったのでandroidstudioを勉強しはじめた.

勉強方法をしらべつつ試行錯誤しているのでそのメモ.

この記事で書きたいこと

  • android学習方法紹介
  • やったことの時系列記録

対象読者

  • androidを勉強し始めたい人
  • 新しい何かを始めたくなった未来の自分

開始時筆者ステータス

cactus-k.hatenablog.com

  • javaは名前しか知らない
  • WSL等のターミナルは触る

環境構築

  • 公式サイトに行ってダウンロードした.

developer.android.com

  • 開けたので問題なさそうと判断し,次に進んだ.

とりあえずhelloworld

  • ダウンロード後公式サイトを眺めていたところ,以下のぺージを見つけたのでやってみた.

developer.android.com

  • 日本語で解説されていてhelloworldまで詰まらずに行けた.うれしい.
  • シミュレータは使わず,手持ちのandroidスマホを開発者モードにして接続してテストした.
  • スマホにアプリが入った.うれしい.

方法の調査と選定

この記事の本題. helloworldの次にやるべきものがすぐに見つからず,しばらく人に聞いたり調べたりした.

調査で見つけた勉強方法とその感触

  • amazonで調べたり,本屋さんで立ち読みしたりした.
  • アプリの本
    • Amazon CAPTCHA
    • 環境構築から丁寧に解説しているものや仕組みの解説が多いものなど様々
    • 手元のandroidstdioバージョンと合わせようとすると選択肢が限られてしまう

ブログ、wiki、動画

  • 作ったものとそのソースコードを書いているブログは多い印象
    • チュートリアル用途には気に入ったのが見つけられなかった
    • 基本を習得してからお世話になりたい

google公式資料

↓のページに求めていたものを見つけた.

developer.android.com

このページを下まで読んでいくと,

その他の学習資料 初心者から熟練者までの Android デベロッパー向け資料をご利用ください。 というのがある.

方法選定

  • 結論から言うと,↓を採用した.

codelabs.developers.google.com

  • 上記を選定した理由は以下.本を買うのと迷った.

    • ひとまずなにが作れるか知りたいので作例がたくさんほしい
    • 画面操作手順・コード両方を解説してほしい
    • 手元の環境とバージョンが同じか極力近い解説が見たい
    • 環境構築はやったらできてしまったので解説なくてよい(本だとここにページを割いているものがわりとある)
    • 動画のように焦らなくてよい,かつ指示通り作業するだけというハードルの低さ(チュートリアル形式の利点)
  • 公式チュートリアルという信頼感

  • まとまった量を順序立てて書かれていそう
  • 英語であることを除けば本と同等のものが無料
  • というのも大きな魅力.

チュートリアル開始

  • 早速選んだチュートリアルを始めた.
  • 画面の通りにすすめるだけ

    • 2019/5/20現在,チュートリアルとandroidstdio最新版に目立った相違点はなさそう
    • チュートリアルに書かれているコードを真似するだけでエラーもなく進められている.
  • チュートリアルで作ったアプリの1つとスマホにたまっていくアプリたち f:id:cactus_k:20190521000458j:plain:w300 f:id:cactus_k:20190521000454j:plain:w300

  • 英語読む気分になれないときは↓のChrome拡張がおすすめ.

  • chrome.google.com
    • アイコンをクリックするとページ全体が翻訳されて楽.
    • 訳された日本語がおかしいときは読みたい文にカーソルを合わせると良い
    • ハイライトされて原文が表示される

f:id:cactus_k:20190521000232p:plain
こんな感じになる

おまけ:javaの本を読み始めた

  • チュートリアルは楽しく進めていて,チュートリアルの解説を読めばコードの事前知識はなくても動かせてしまう.

    • でも,ちょっとすっきりしない
    • 「(知らない単語)が(知らない単語)だから(知らない単語)になります.」という状況
  • そこで,androidアプリ開発本を探していたときにAmazonでおすすめされた本を眺めはじめた

  • 平易な例で概念を丁寧に説明してある.オブジェクト指向が(自分の中では過去最も)わかった気分になった(わかったとは言っていない...).

  • 実用に振ったgoogleチュートリアルと組み合わせて使うのにちょうど良いように感じた.

まとめ

困っていること

  • ここまで書いたけど,「Android Developer Fundamentals Course」の次にやるとよさそうな教材が見つけられていない.
  • いいのあったら教えてください

今後やりたいこと

  • さぼてんの観察日記アプリでもつくりたいなあと思っている.

ミスミメンテbotをつくった(簡易版)

つくったもの

twitter.com

  • メンテ予告をつぶやいてくれるtweetbotを作った.
  • 今のところ,メンテの有無にかかわらず,1日1回つぶやく仕様.

ミスミメンテとは

https://jp.misumi-ec.com/jp.misumi-ec.com

  • 機械部品とかが買えるサイト.何かとお世話になる機会が多い.
  • 時々メンテをしていて,作業しようと思ってメンテだと悲しくなる.
  • トップページの上部で予告はされるので確認すればよいのだが,忘れがち.

仕様・しくみ

使用言語とか

  • python3
  • ちなみにpython2で作り始めたところ,文字列まわりの扱いが悲しいことになった(使いたいものが使えず文字化けが解決できなかった).

メンテ判定

  • トップページ上部のお知らせ欄にメンテナンスの文字があるかを調べ,その行の日時の文字列(=予定日時)を抽出.
  • お知らせ欄のXPathchromeデベロッパーツールから調べた.
  • お知らせ欄全体ではなくメンテナンスの行の日時を抽出しているのは災害等による輸送遅延なども書かれる場合がある為

ツイート

ifttt.com

  • 使い慣れているiftttのwebhookを使った.
  • プログラム側から引数を与えることはできるが,ツイート内容の細かい設定はifttt側で行う.
  • 利点
    • プログラム上では1行でツイートできる
  • 欠点
    • ソースコードとappletの両方を管理しないといけないのが面倒.辻褄があっていないとバグる.
    • ツイートの種類を増やそうとするとappletが増えていくのが面倒
    • ツイート内容の自由度が低い
  • ただただ気楽に使えるのが良さ.

定期実行

www.heroku.com

  • 「アプリの構築、提供、監視、スケールに役立つクラウドプラットフォーム」らしい
    • 今回初めて触った,詳しくない...
  • tweetbotの作り方を調べたり聞いたりするとわりとこれが使われている.
  • 基本無料
  • スケジューラのアドオンを使うと無料で定期実行できる
    • アドオンを使うにはクレジットカード(デビットカードでもいけた)の登録が必要ぽい

ソースコード

  • よい書き方じゃないかもなので注意
  • url.py gist.github.com

  • runtime.txt

    • python-3.x.xの数字は公式ドキュメントに書いてあるものにする
    • 2系か3系かだけそろえれば以降の数字は手元のバージョンではなく公式ドキュメントの方に合わせる
    • 今回は3.7.2
python-3.7.2
django
gunicorn
django-heroku
lxml
requests
  • Procfile
web: gunicorn misumi-tweet.url --log-file -

今後改善したいこと

  • ifttt使わず直接tweet
    • 設定を一元管理したい
    • ツイート内容のバリエーション増やしたい
  • メンテ中のツイートにメンテ終了時刻を表示
    • 当然メンテ中はアクセスできない(=時刻を取得できない)のでメンテ前にメモっておく仕組みが必要そう

参考にしたページ

ページ内容取得関連