まるぼ実験場

今年専門を卒業したけど就活サボってしまいました(関係ない職種でフリーター生活中)。どうすんだよこれ。

Arduinoでアーケードスティック(LS-32-01)をPCに繋いで簡易アケコン的に遊ぶ

最近アーケード格ゲーを触って、ちょっとコマンド練習してみたいなーと思ったのだが、
練習用にアケコンを買うにも高いし。今ストリートファイター6需要でどうも品薄っぽいし。てかまず部屋に置き場所ないし。

格ゲーやるなら家庭用とかでええやん、ってなるかもだけど、自分の場合ただ格ゲーをガチりたいわけではなく、
ふらっと友達や家族とゲーセンに行ったときに一緒に遊べるゲームを増やしたいなー程度で練習しておきたいというだけなのである。
なので正直今更アケコン買うほどか?と思うところもあるし、家庭用なら別にパッドでもいいと思ってる(というか多分パッドやキーボード操作のが上手い……)
ということでゲーセン版への拘りがあるので、どうしてもアーケード仕様のスティックには慣れる必要がある。スティック操作さえ練習できれば……。
いや、昔なら現地でお金積んでみんな上手くなっていったんだろうけども……。

そこで閃いたのだった、アーケード仕様のスティックだけならパーツ屋行けば単品で買えるやん。
このスティックをPCに接続し、ボタン操作はPCのキーボード操作でカバーすれば省スペースローコストにスティック操作を練習できるのでは?
今の時代のトレンドは自作アケコンだとも聞いたことがある!

買ったもの

セイミツ工業 LS-32-01

スティック本体は個人のお好みのものを。機種によって端子の種類や取り付け可能ベースが変わったりするのでその辺は注意。
筆者はまだあんまり分からないが、機種毎にクリック感の違いとかあるようでなかなかの沼を感じる。
よく行くゲーセンのと同じ機種にしても良かったかもしれない。格ゲーなら三和電子製がお好みな人のが多いのかな?

レバーボール

付いてなかったので。

5Pハーネス

↑のLS-32-01はコネクタ接続タイプだったので購入。

薄めのMDF合板、ベース用ネジ

そのうち外側を作るため。

マイコンに接続


本体にハーネスを繋ぎ、橙の線をArduinoのGND、
他の線を適当なデジタル入力に接続してシリアルモニタで入力をチェックした。
ハーネスが右上として、入力の方向と出力の内容を以下のソースコードの出力によって確認した。

const int PIN_A = 2; //緑
const int PIN_B = 3; //黒 
const int PIN_C = 4; //赤
const int PIN_D = 5; //黄

void setup() {
  // put your setup code here, to run once:
  pinMode(PIN_A, INPUT_PULLUP);
  pinMode(PIN_B, INPUT_PULLUP);
  pinMode(PIN_C, INPUT_PULLUP);
  pinMode(PIN_D, INPUT_PULLUP);

  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  int val_a,val_b,val_c,val_d;

  val_a = digitalRead(PIN_A);
  val_b = digitalRead(PIN_B);
  val_c = digitalRead(PIN_C);
  val_d = digitalRead(PIN_D);

  Serial.print(val_a);
  Serial.print(val_b);
  Serial.print(val_c);
  Serial.print(val_d);
  Serial.println();

  delay(500);
}

結果まとめ

格ゲーライクにテンキー表記。

7:1010 8:1011 9:1001
4:1110 N:1111 6:1101
1:0110 2:0111 3:0101

……なんとなくビットで処理してみたくなる文字列が出てきましたね。
各方向の入力が特定できたので、それをパターンわけしてキーボードとして入力すればできそうだ。

ソースコード

#include <Keyboard.h>

//セイミツ工業LS-32-01使用、ハーネスを右上とする
const int PIN_A = 2; //緑
const int PIN_B = 3; //黒 
const int PIN_C = 4; //赤
const int PIN_D = 5; //黄

const int INPUT_1 = 6;  //0110
const int INPUT_2 = 7;  //0111
const int INPUT_3 = 5;  //0101
const int INPUT_4 = 14; //1110
const int INPUT_5 = 15; //1111
const int INPUT_6 = 13; //1101
const int INPUT_7 = 10; //1010
const int INPUT_8 = 11; //1011
const int INPUT_9 = 9;  //1001

boolean state_down, state_up, state_left, state_right;

void setup() {
  // put your setup code here, to run once:
  pinMode(PIN_A, INPUT_PULLUP);
  pinMode(PIN_B, INPUT_PULLUP);
  pinMode(PIN_C, INPUT_PULLUP);
  pinMode(PIN_D, INPUT_PULLUP);

  Keyboard.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  int val_a,val_b,val_c,val_d;

  val_a = digitalRead(PIN_A);
  val_b = digitalRead(PIN_B);
  val_c = digitalRead(PIN_C);
  val_d = digitalRead(PIN_D);

  int input;
  input = val_a << 3;
  input = input | (val_b << 2);
  input = input | (val_c << 1);
  input = input | val_d;
  
  switch(input){
    case INPUT_1:
      state_up = false;
      state_down = true;
      state_left = true;
      state_right = false;
      break;
    case INPUT_2:
      state_up = false;
      state_down = true;
      state_left = false;
      state_right = false;
      break;
    case INPUT_3:
      state_up = false;
      state_down = true;
      state_left = false;
      state_right = true;
      break;
    case INPUT_4:
      state_up = false;
      state_down = false;
      state_left = true;
      state_right = false;
      break;
    case INPUT_5:
      state_up = false;
      state_down = false;
      state_left = false;
      state_right = false;
      break;
    case INPUT_6:
      state_up = false;
      state_down = false;
      state_left = false;
      state_right = true;
      break;
    case INPUT_7:
      state_up = true;
      state_down = false;
      state_left = true;
      state_right = false;
      break;
    case INPUT_8:
      state_up = true;
      state_down = false;
      state_left = false;
      state_right = false;
      break;
    case INPUT_9:
      state_up = true;
      state_down = false;
      state_left = false;
      state_right = true;
      break;
  }
  /*
  state_up ? Keyboard.press(KEY_UP_ARROW) : Keyboard.release(KEY_UP_ARROW);
  state_down ? Keyboard.press(KEY_DOWN_ARROW) : Keyboard.release(KEY_DOWN_ARROW);
  state_left ? Keyboard.press(KEY_LEFT_ARROW) : Keyboard.release(KEY_LEFT_ARROW);
  state_right ? Keyboard.press(KEY_RIGHT_ARROW) : Keyboard.release(KEY_RIGHT_ARROW);
  */
  
  state_up ? Keyboard.press('w') : Keyboard.release('w');
  state_down ? Keyboard.press('s') : Keyboard.release('s');
  state_left ? Keyboard.press('a') : Keyboard.release('a');
  state_right ? Keyboard.press('d') : Keyboard.release('d');
  
  delay(1);
}

アケコンのスティックの入力はボタンとは異なり、倒された時には押されっぱなしになる必要があり、
入力ナシになるのがレバーニュートラル(真ん中)の状態のみである。
なので基本はKeyboard.pressを使用する必要があるが、入力の方向が変わったときにはKeyboard.releaseを入力しなければならない。
パターン分けするのは大変そうだったので、4方向分の入力情報を持たせて最後に纏めて処理させる事にした。

ここであることに気づいた

ところで先述の表をもう一度見て欲しい。

7:1010 8:1011 9:1001
4:1110 N:1111 6:1101
1:0110 2:0111 3:0101

……よく見ると法則が見えてこないだろうか。

ニュートラル時は固定で全て1、
スティックが、
下方向に入力されているときは1桁目が0、
上方向に入力されているときは2桁目が0、
右方向に入力されているときは3桁目が0、
左方向に入力されているときは4桁目が0、
斜め方向の場合、両方向の積を取った値になっていた、ということに気がついた。
これならソースコードをさらにシンプルにできる。

ソースコード・改

#include <Keyboard.h>

//セイミツ工業LS-32-01使用、ハーネスを右上とする
const int PIN_A = 2; //緑
const int PIN_B = 3; //黒 
const int PIN_C = 4; //赤
const int PIN_D = 5; //黄

void setup() {
  // put your setup code here, to run once:
  pinMode(PIN_A, INPUT_PULLUP);
  pinMode(PIN_B, INPUT_PULLUP);
  pinMode(PIN_C, INPUT_PULLUP);
  pinMode(PIN_D, INPUT_PULLUP);

  Keyboard.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  int val_a,val_b,val_c,val_d;

  val_a = digitalRead(PIN_A);
  val_b = digitalRead(PIN_B);
  val_c = digitalRead(PIN_C);
  val_d = digitalRead(PIN_D);
  
   /*
  val_b == 0 ? Keyboard.press(KEY_UP_ARROW) : Keyboard.release(KEY_UP_ARROW);
  val_a == 0 ? Keyboard.press(KEY_DOWN_ARROW) : Keyboard.release(KEY_DOWN_ARROW);
  val_d == 0 ? Keyboard.press(KEY_LEFT_ARROW) : Keyboard.release(KEY_LEFT_ARROW);
  val_c == 0 ? Keyboard.press(KEY_RIGHT_ARROW) : Keyboard.release(KEY_RIGHT_ARROW);
  */
  
  val_b == 0 ? Keyboard.press('w') : Keyboard.release('w');
  val_a == 0 ? Keyboard.press('s') : Keyboard.release('s');
  val_d == 0 ? Keyboard.press('a') : Keyboard.release('a');
  val_c == 0 ? Keyboard.press('d') : Keyboard.release('d');
  
  delay(1);
}

入力を判定していたところがごっそりと消えてしまった(笑)サンプルコード並のシンプルさ。
いやまぁ、最終的にやったことってdigitalReadしてキーボード入力にパスしただけ……。

いちおうPC版メルブラの初心者ミッションをこのスティック繋いでやってみて、だいたい達成出来たから方向キーの入力に関しては大丈夫だろう、たぶん。キーボードと入力が混信せずにちゃんと入力されてそう。(ただし筆者の腕前はお察しなのでそう言い切るのは不安である)

MELTY BLOOD: TYPE LUMINA - PS4

MELTY BLOOD: TYPE LUMINA - PS4

  • ディライトワークス
Amazon

これでスティック部分のプログラムはOKかなってところで。
てかここにボタンを足したらまんまアケコンができてしまいそうよねw

あとは操作中にスティックが動かないように外側の箱もつくらないとかなー。

※続き
marubodiary.hateblo.jp

ヤフオクの発送方法に迷ってる人へ

梱包したもののサイズを入力すると、使えそうな配送手段を提案するWebアプリ作りました。

3ka.me

7/31更新

・新しい発送方法(ゆうパケットポストmini、ゆうパケットプラス)に対応、料金改定に対応

 

PHPJavaScriptの習作。基本判定部分はPHP。オールJavaScriptではないメリットとしては、サーバーサイド処理を挟む事によって環境依存を減らせる、という点になるのかなぁと。

・おまけとしてサイズのイメージを表示する機能を搭載

『まる募』ソースコードダウンロードできるようにしました

以前から言っていた、『まる募』のデータ供養。

ダウンロードはこちら(Zip形式)

 

marubodiary.hateblo.jp

 

ファイル構成

/app

⌞/models

  database.py データベース接続用設定

  models.py DBモデルデータ

  ⌞/settings

     .htaccess

     __init__.py

     dbsettings.py  データベースのユーザー名、パスワードなど

 ⌞/static

 ⌞/templates htmlファイルのテンプレートを格納

 .htaccess

 app.py ほぼこれが本体

 index.cgi サーバーでFlaskを動作するために必要

 bottweet.py ボットツイート用。Cronで定期動作させていたスクリプト

 twitter_api.py app.pyから呼び出されるツイッターAPI絡みのスクリプト

マインスイーパー アレンジゲーム開発記録

マインスイーパーをアレンジしたRPG風ゲームを制作中。

制作言語:JavaScript

Version1 プロトタイプのプロトタイプ

ふぁじいすいーぱー(仮)(開発終了)

マインスイーパーのルールをアレンジしたゲームを作ってみたかった。

Version2 一人称視点風に

ふぁじいすいーぱー(仮) ~新米スイーパーの冒険編~(開発終了)

・マップ表示、システム、ルールの見直し

スマホでも遊びやすいように改修

Version3 よりRPG風をめざして

ふぁじいすいーぱー(仮) ~新米スイーパーの冒険編~

(こちらのバージョンを主に現在更新中。。)

・グラフィックを差し替え、表現の向上を目指す

・世界観に合わせたテキストへと見直し。さらにRPG的要素を取り込む

 

今後やりたいこと

・グラフィックの向上(現在進行形)

・戦闘システムの実装

・アイテムの実装

・ランキングシステムや協力システムなどオンライン要素の実装

某家電量販店でバイトを始めた

家電量販店バイトを始めてしばらく経ったので、よかったこと課題など記録しておこうと思う。

最初になぜかレジに回されてレジしかやってません。みんなが思い浮かべるような販売の仕事はしばらくやることはないかな?

 

よかったこと

・研修資料などはしっかりしていた

Webでの研修教材と本がしっかり存在。一応いきなり売り場に出されるわけではなかったのでその辺は安心だったかもしれない。この辺の整備は流石大手と言うべきか。
ただし、最初にちょっとやっただけであんまりその辺に時間を割いてはくれない(そのへんは店によるかも)。

・シフトの都合は結構聞いてもらえる

土日はなるべく出て欲しい雰囲気であるが、月一、二回程度なら事前にお願いしておけば土日休み貰える雰囲気。(多分店の人員足りてるかにもよる)
土日休んでもどうせ大して特別なことしない、平日休みのが個人的に都合良い自分にとってはこれで十分。

・深夜勤務、早朝勤務がない

レジや売り場なら朝は9時10時くらいから入ってる人が多い、夜もあんまり夜遅くまでやってる店は少ない印象なので人間的な生活を維持できる。

・土日祝時給アップ

土日祝たいしたことしてないなら仕事するわと。時給上がるから。

・食品を扱うことがほとんどない

出されたものは残さず全て感謝して食べるように教育されていた自分にとって、飲食やスーパーやホテルだと食品が毎日大量廃棄になることで病みそうだと思ったから。

・社員割引でいろいろ安く買える

ほぼ卸値とかなんとかという噂。まぁお金ないからなんも買えんけど。正直ものによってはAmazonと大差無いどころかそっちのが安いことも多い

・趣味の知識が役にたったりする

携帯が好きならiPhone各モデルの特徴や搭載端子を判別できるスキルとかめっちゃ役にたつと思う。あとアニメ好きとかで映像サブスクとかやってると布教もできる(サービス加入が取れると実績になって喜ばれるらしい)

・立ち仕事

自分は前職で居眠りが多く、勤務態度が良くないとしょっちゅう注意されていたり睡眠障害を疑われるまであったので……。立ち仕事なのもあってか、眠気とは無縁で働けている。

ただ、この点に関しては昼からの勤務になったところも大きいかもしれない。(朝ゆったりできるため眠気の原因となる糖質や添加物に配慮したような弁当が作れる、前職でも夕方あたりに調子が良くなっていた自覚があったため)

 

難しかったところ

・覚えることの独特さ

まだレジしかやってないが、難しいと噂されるコンビニなどとはまた違った難しさがあると思う。

レジしかやってないとはいえ、レジだけでやることどんだけあんねん!ってなっている。

商品などの注文(専用システムを覚える)、修理の受付(修理になると思ってたら別の処理に分岐したりする)、リサイクルの受付……。これらを客とのコミュニケーション合わせてこなさねばならない。

あとはレジ中に質問受けることが多いこと。自店のポイント制度やクレジットカードの機能を説明したり、店頭で扱えるサービス、商品の内容について口頭で伝えることとかちゃんと伝えないとトラブルやクレームになることとか……。
もともと家電オタクで日常的にその店通ってる会員とかならついて行きやすいかと。むしろこんなサービスあったの!?って驚きの仕様をバイトで入り始めて始めて知ったり。

あと自分はやったことないけどもちろんレジ以外の部門(売り場の販売員、倉庫担当、などなど)もある。それらの仕事全部覚えてる人は社員さんくらいだと思う。

逆に言えば、普通のバイトは覚えること少なくてすぐ飽きてしまう、って人は是非うちのとこ来て欲しい。やることが多いしおもしろいお客さんやがっつりおしゃべりする機会もあるから飽きないかもよ!

・丁寧な接客が求められる

比較的高額な商品を扱うのもあって、商品や保証について念入りに説明するような場面が多い。ポイントカードの所持の有無とかも、ファーストフード店よりはちゃんと聞かないといけないなど……。
ちゃんとした人はまずお世話にならないような、会員限定の救済制度みたいなのもやたらとあったりする。
真面目な人にはお勧めかもしれない。

・立ち仕事

これは元々体力ない自分が悪いところはある。

 

不安なこと

・時給に夢がない

時給アップ制度はあるのだが、そもそも天井額になる条件が自分にとっては厳しそう。そしてその金額もあんまり高くはない。3年ほど続けてるらしい先輩にやんわり聞いても、新人の自分より数十円高いくらいだそう……。

あんだけできるのに?嘘だろ?って時給考えるたび思ってる。

・コミュ障すぎる

お客さんの意図をくみ取ることがうまくできないことがあってキレられたり、頑張ろうと思うあまり勧誘がしつこいとキレられクレームになったり、コミュニケーションの下手くそさをどうしても感じてしまう。
思ってもない事を言われると自分が言おうとしてた事が飛んでしまったりとか。

まぁ先輩がヘルプしてくれるうちはなんとかやっていけているが……。年下にフォローされて心がしんどい

 

1年ぶりの勤務、社会復帰リハビリのつもりで社会保険に入れるギリギリ、週4日程度で勤務している。

やってみて分かったのはしばらく自分はまともな仕事に就けそうにない。

元々夜型人間の傾向があったのだが、昼からの勤務にすることで毎朝感じていたストレスが大分軽減された。
また、休むことがどうも下手だったのだが、週休3日で時間は取れるので自分がやりたいことと、嫌でもやらなくてはならないこと、休むことのバランスがなんとか取れている。

勤務時間が短いのもあって給与面については不安しか無いけど……。うっかり食べ過ぎると赤字生活です……。
調子良いときに単発バイト掛け持ちするとかできんものかねぇ。自分がやりたいことと近い好きなこと、例えばプログラミングとかで短期単発の仕事無いもんだろうか。

 

正直フルタイムで働いていたときよりかは生きてる、って感じがしてる。前述の様に時間が持てるようになったので、自分がやりたいと思っていた事ができるようになったのと、休みが多いからか調子も良い。

接客業は他人と関わりすぎて疲れると感じることもあるが、自分のことを深く知らない、知る必要も無い人々と関わることで、組織に溶け込むために今まで殺してきた、自分らしいところも戻してこれた気もする。

まぁこれで勤務することに慣れていって、ゆくゆくはフルタイム勤務正社員に戻れればいいなぁ……。フルタイムに戻ると、自分のやりたいことをある程度諦めるしかないのかもしれんけどね。

ところでこのバイトを始めたことで、勤務の仕方、自分にはどういう働き方が合いそうかにつていて身をもって色々発見できたのは大きいかもしれない。

学生時代親の意向でバイトさせてもらえなかったので、こういうことを理解せずに普通に就職してしまったところはどうしても引っ張ってたかもしれない……。

また、完全未経験であった接客業という分野に踏み入れるきっかけをくれた店長には感謝している。自分の可能性を試すためにも、もう少し続けてみたい、と考えていたのだった。

M5StickCでバイブレーションタイマーを作りたい

自分が欲しいタイマー

自分が今やっているバイトは休憩時間が不定で、日によって休憩に入る時間が異なる。
なので、自分で休憩時間を管理する必要がある。
バイトの休憩時間を活用して積み読崩したり勉強したりしていきたいのだが、まぁ、時計が気になって集中出来ないこと。

音が出るタイマーでは他の人の迷惑になってしまうので、バイブレーションで設定時間を伝えるタイマーとかあったら良いんじゃないだろうか、と考えた。たとえば図書館のような時間を忘れがちな環境で使えるタイマー……。
スマートフォンのアラーム機能でもいいと思うが、前述のように毎回時間が異なり、一々設定するのは手間なのでなにか考えてみることにした。

検討した方法

最初はスマホアプリとして作ろうと考えたが、
ウィジェットとしてホームに置けて一回ボタン押しただけで設定できるようにしたい……ウィジェットってどうやって作るんだ?と調べるも手持ちの資料には載っていなくてめんどそうだったのでそこで壁にぶつかり中止。
あとスマホを開くならついでに……とついつい別のことをしてしまいそうなのがよくない。

なので久々の電子工作で行くことにした。

一応作る前に、キッチンタイマーあたりでバイブレーション機能が付いているものが存在しないか確認しに行ってみた。大手ではタニタさんが出しているようだ。コレ良さそう。
手持ちの部品かき集めれば新たに買うより安価にできそう&もっとシンプルなものが良いのと個人的に欲しい機能が無いので自作してみることに。値段によってはここで記事が終わってた可能性。

最初はAVRあたりを使って実装しようかな、と思っていたのだが、
・ワンボタンですぐ使えるようにしたい
・筐体は電源含めて胸ポケットに入るくらい(お菓子ケースくらい)が良い
・残り時間表示用に7セグなどあれば尚良し

……ここまで考えて、よくよく考えれば家にあんまり活用されていないM5StickC(注・うちにあったのはPLUSじゃないほう)があったじゃないか!

M5StickCならば本体にボタンと画面とLEDと内蔵電源があるので、振動モーターだけを調達してポン付けすればほぼほぼ目的を達成できそう。これを使って実装しようと考えた。

振動モーターの調達

一気に完成形が見えてきた。
問題はモーターの調達方法だが、秋月電子とか共立エレショップとかを眺めながら、あー部品一つで送料かかるのめんどくさいなー日本橋行きてぇなーなどと呟きながら、
このときの自分は何を思ったのか、壊れた携帯のバイブレーションに使われる部品を再利用できないかと考えていた。
星形ネジや接着剤と格闘すること小一時間……。


どう見ても秋月にある部品(通販コード:P-06784)を発見!60円と送料浮いた!ラッキー!

プログラミング

振動モーター自体の使い方はシンプルで、G26とGNDに繋ぎ、G26から3Vの電気を流している間バイブレーションする。
プログラムの流れは、時間を設定しているとき、設定時間になって電気流してるとき、タイマーで待機してるとき、という状態に分けて考えた。
下にソースコード。PLUSじゃないほうのM5StickC用です。

#include <M5StickC.h>

#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */

RTC_TimeTypeDef RTC_TimeStruct;

enum State{
  STARTSETTING,
  READY,
  VIBRATION,
  TIMECHECK,
};
enum State state_mode = READY;
uint64_t Timer_min = 1;
long lefttime;
unsigned long startMillis,ElaspledMillis,nowMillis;
int wait_lefttimedraw_time = 3000;
int wait_vibrationswitch_time = 2000;
int vibration_count = 0;

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Axp.ScreenBreath( 12 );
  M5.Lcd.fillScreen(BLACK);
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason){
    case ESP_SLEEP_WAKEUP_EXT0:   // deepsleepから起動
      state_mode = TIMECHECK;
      startMillis = millis();
      break;
    case ESP_SLEEP_WAKEUP_TIMER : // タイマー指定時間が経った
      state_mode = VIBRATION;
      pinMode(M5_LED, OUTPUT);
      pinMode(26, OUTPUT);
      startMillis = millis();
      vibration_count = startMillis;
      break;
    default:                      // 電源OFFから起動
      // 初期時刻セット
      RTC_TimeTypeDef TimeStruct;
      TimeStruct.Hours   = 1;  // Set the time.
      TimeStruct.Minutes = 00;
      TimeStruct.Seconds = 00;
      M5.Rtc.SetTime(&TimeStruct);
      state_mode = STARTSETTING;
      startMillis = millis();
      break;
  }
}

void loop() {
  M5.update();
  nowMillis = millis();
  ElaspledMillis = nowMillis - startMillis;
  
  switch (state_mode){
    case READY :
      // 実装予定
      break;
    case STARTSETTING :
      M5.Lcd.setCursor(10, 0, 2);
      M5.Lcd.printf("Timer Set: %02d min", Timer_min);
      
      if(ElaspledMillis > wait_lefttimedraw_time){
        // タイマーセット
        pinMode(GPIO_NUM_37, INPUT_PULLUP);
        esp_sleep_enable_ext0_wakeup(GPIO_NUM_37, LOW);
        esp_sleep_enable_timer_wakeup(SLEEP_MIN(Timer_min));
        
        // ディープスリープ開始
        M5.Axp.SetSleep();
        esp_deep_sleep_start();
      }
      break;
    case VIBRATION :
      M5.Lcd.setCursor(40, 0, 2);
      M5.Lcd.println("it's time!!");
      
      // バイブレーション&LED点灯開始
      if(ElaspledMillis - vibration_count < wait_vibrationswitch_time){
        dacWrite(26, 255);
        digitalWrite(M5_LED, LOW);
      }else if(ElaspledMillis - vibration_count < wait_vibrationswitch_time * 2){
        dacWrite(26, 0);
        digitalWrite(M5_LED, HIGH);
      }else{
        vibration_count = ElaspledMillis;
      }
      
      if(M5.BtnA.wasReleased()){
        // ボタンが押されたとき
        state_mode = READY;
        digitalWrite(M5_LED, HIGH);
        M5.Lcd.setCursor(40, 0, 2);
        M5.Lcd.println("Timer Stop\n");
        delay(1500);
        M5.Axp.PowerOff();
      }
      break;
    case TIMECHECK :
        // 残り時間を表示
        M5.Rtc.GetTime(&RTC_TimeStruct);
        lefttime = (Timer_min * 60) - (RTC_TimeStruct.Minutes * 60) - RTC_TimeStruct.Seconds;

        M5.Lcd.setCursor(20, 0, 2);
        M5.Lcd.printf("Left Time: %02d", lefttime);

        // 表示時間終了後、再スリープモードに入る
        if(ElaspledMillis > wait_lefttimedraw_time){
          pinMode(GPIO_NUM_37, INPUT_PULLUP);
          esp_sleep_enable_ext0_wakeup(GPIO_NUM_37, LOW);
          esp_sleep_enable_timer_wakeup(lefttime * uS_TO_S_FACTOR);
          // ディープスリープ開始
          M5.Axp.SetSleep();
          esp_deep_sleep_start();
        }
        break;
      default:
        break;
  }
}

(電源を入れる)
時間を設定
タイマースタート
スリープ状態へ移行
設定時間後、スリープを解除しバイブレーションする。
ボタンを押すとバイブが止まる
(電源を切る)
以上がメインループとなっており、
スリープ中にボタンを押すことで残り時間を表示する機能を付けている。
電池の節電のことを考えてディープスリープを使ってみた。
長時間を想定したタイマーなので、なるべくRTC(内蔵時計)を使ったほうが良いのかな?と考え実装してみたが、スリープ復帰時にタイマーを再計算する事によってズレたりとか精度はどうなのかちょっとよく分からない。

改善・確認したいところ

・長時間の精度はどんなものなのか実際の休憩時間に使って確認したい。ボタンを押すたびにスリープ時間を再設定しているので、繰り返すとバグったりしやしないかと。
・実験中に振動モーターの足が折れてしまったので結局実装できず。本体への固定方法も考える必要がある。
・5min、10min、60minから選べる時間設定機能を付けたい。
・本体設定の時刻を起動時にリセットしてしまっているので、実際の時刻を入れられるようにして時計としても使えるようにしたいところ。(計算式の変更が必要になりますね……)

あとはスリープ状態への移行は任意のほうがいいかも?と思ってたり。
丸々1日+αでM5Stickと格闘してなんとか欲しいものと近いものが形になったと思う……(休日一日で済んで良かったなホント)

『まる募』はサービスを終了しました

一応サイトの方や紹介記事とかにも書いたのですが、こっちにも新規記事で。

マルチプレー募集掲示板『まる募』はサービスを終了致しました。

 

終了理由

レンタルサーバーの値上げ

ロリポップのスタンダードを12ヶ月で契約していたのですが、
それが3月以降には 660円/月→770円/月に改訂になるとか。年額にすると7920円→9240円。

いやーちょっときっついな……。

いまより長期の契約にする案もあったのですが、一回の支払いがきついのと、レンタルサーバーの価格競争の熾烈さを知っていると12ヶ月ごとに見直すのが丁度良いんだよなぁと。

そもそも、ロリポのサーバースペック使いこなせていたか?ってことで考えると、PythonSSHMySQLが必要なのって主にこれのせいなんだよね。ほかは昔懐かしの掲示板置いてる程度でほぼほぼテキストサイトのそれだし。

Pythonを切るだけで選べるレンタルサーバーの選択肢が広がるという。趣味で遊ぶならやっぱPHPよ。VPS?凝り性な私はコンテンツより管理でいっぱいいっぱいになってしまう可能性があるので……(いまだに発信にはてブロも併用してる理由もそれだったり)。

というわけで、まる募を切ってもっと安くてスペック抑えたサーバーに他コンテンツだけ持って行きます。まる募のドメインは期限切れそのまま解約します。

そして本サイトの方は、元々ロリポップの会社が持っていたドメインだったのでURLが変更になりますが、その代わり独自ドメインを取ったので、今後はURLを使い回していこうかなと。

・TwitterAPIに関するゴタゴタと有料化

まぁまる募だけなら、PythonSSHが使える格安サーバー(コアサーバー)に移行するという手も無くは無かったのですが……

そこにTwitterAPIの締め出しとか有料化とかなんちゃら。……それで終了することに決めました。サーバーからは全ファイル削除済みです。

Twitter連携のマルチプレー募集掲示板ってのがウリなのに、Twitterとの連携機能が無くなったらただの掲示板でよくね?って思っちゃったのよね。

・そもそも利用者がそんなに(ry

終了しても誰も困らないだろうから。

このアプリを作って学んだこと。

・試験環境のSQliteから本番環境のMySQLへののせ替え

なるほど、最初にデータ構造を書いておくやつはこんな時に生きるのかーと。
SQliteはいろいろ格納できるんだけど、その辺でちょっと注意する事があることも学んだ(MySQLはバージョンによっていろいろ変わるとこが出るとか……)

・Flaskはたのしい

LaravelやDjangoとかと比べて個人サイトとかでも扱いやすいと思った。練習にも良いと思う。
ただ、個人向けで対応しているレンタルサーバーが少ないのがどうしても……

・OAuthの実装

最初はOAuthのライブラリがなんたら~……みたいな感じで実装していたのですが、
Tweepyすげー、簡単じゃん!!感動。

・BootStrapは偉大

デフォでBootStrapを使ってくれるんだけど、これすごいね。
デザインの知識皆無なのに良い感じにしてくれた(某スクールの先生に見せたら、これ普通に就活出来るレベルでは?と言ってもらえた)

……就活に使うつもりだったのにサ終しちゃったからなー。ポートフォリオどうしよ。

 

……ってところかな。

上記の就活の件もあるし、最終版のソースコードもどっかに投げようと思う。