【ラズパイ】スイッチ操作を割り込みで行う。

最新ソースはこちら。

https://github.com/takishita2nd/RaspiDisplayMonitor

以前使用していた12個のスイッチは3つの信号と4つの制御線の組み合わせで検出していましたが、

いまはスイッチは1個なので、エッジの割り込みで操作できるはずです。

スレッドが一つ無くなるので、ラズパイZeroでも動作が軽くなると思います。

import RPi.GPIO as GPIO
import time
import datetime
import calendar
import GLCD
import AM2320
import Weather

sw = False

def __main__():
    global sw
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(22,GPIO.IN) 
    GPIO.add_event_detect(22, GPIO.FALLING, callback=callback, bouncetime=300)
    GLCD.PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCD.GLCDInit()
    GLCD.GLCDDisplayClear()

    roop = 10 * 60 * 60
    mode = 1
    try:
        while True:
            if sw == True:
                GLCD.GLCDDisplayClear()
                mode += 1
                if mode > 3:
                    mode = 1
                sw = False

            if mode == 1:
                if roop >= 10 * 60 * 60:
                    GLCD.GLCDDisplayClear()
                    Weather.RequestAPI()
                    weather = Weather.GetWeather()
                    temp = Weather.GetTemp()
                    roop = 0

                GLCD.GLCDPuts(1, 0, "Date :")
                GLCD.GLCDPuts(5, 8, datetime.datetime.now().strftime('%Y:%m:%d %A '))
                GLCD.GLCDPuts(1, 16, "Weather :")
                GLCD.GLCDPuts(10,24, weather)
                GLCD.GLCDPuts(10,32, "Temp : " + format(temp) + 'C')
                GLCD.GLCDPuts(1, 40, "Time : " + datetime.datetime.now().strftime('%H:%M'))
                GLCD.GLCDPuts(1, 48, "Humidity    : " + AM2320.GetHum() + '%')
                GLCD.GLCDPuts(1, 56, "Temperature : " + AM2320.GetTemp() + 'C')

                roop += 1
            elif mode == 2:
                cal = calendar.month(datetime.datetime.now().year, datetime.datetime.now().month)
                cals = cal.split("\n")
                y = 0
                for c in cals:
                    GLCD.GLCDPuts(1, y, c)
                    y += 8
            
            elif mode == 3:
                GLCD.drowMashiro()

            time.sleep(1)
    except KeyboardInterrupt:
        GLCD.GLCDDisplayClear()
        GPIO.cleanup()

def callback(channel):
    global sw
    sw = True

__main__()

GPIO.add_event_detect()で割り込み処理の登録を行います。

監視するGPIOの番号、エッジ(HIGH/LOW)、コールバック関数、検出間隔指定します。

上の処理では、GPIO22が下りエッジを検出したらcallback()が実行されます。

スイッチ検出がかなりスムーズになりました。

【Laravel】【ダイエット支援】【食事管理】入力ダイアログを作成する

前回までの状況はこちら。

最新ソースファイルはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

入力ダイアログの画面を作成していきます。

ベースは体重管理で作成したものを使用します。

実際の処理は後で作成します。

EatingInputDialogComponent.vue

<template>
    <div>
        <div id="overlay" v-show="show">
            <div id="content">
                <p v-if="error_flg == true" class="error">
                    <ui>
                        <li v-for="error in errors">{{ error }}</li>
                    </ui>
                </p>
                <table class="edit">
                    <tbody>
                        <tr>
                            <td>品名</td>
                            <td><input type="text" v-model="contents.item" /></td>
                        </tr>
                        <tr>
                            <td>タンパク質</td>
                            <td><input type="number" v-model="contents.protein" /></td>
                        </tr>
                        <tr>
                            <td>脂質</td>
                            <td><input type="number" v-model="contents.riqid" /></td>
                        </tr>
                        <tr>
                            <td>炭水化物</td>
                            <td><input type="number" v-model="contents.carbo" /></td>
                        </tr>
                        <tr>
                            <td>カロリー</td>
                            <td><input type="number" v-model="contents.calorie" /></td>
                        </tr>
                    </tbody>
                </table>
                <p id="command">
                    <button @click="clickAdd">入力</button>
                    <button @click="closeModal">閉じる</button>
                </p>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    props: ['show'],
    data() {
        return {
            errors: [],
            error_flg: [],
            param: {},
            contents: {
                item: "",
                protein: "",
                riqid: "",
                carbo: "",
                calorie: "",
            },
        };
    },
    created: function() {
    },
    methods: {
        clickAdd: function() {
        },
        closeModal: function() {
            this.$parent.showInputDialogContent = false;
        },
        clear: function() {
            this.contents.item = "";
            this.contents.protein = "";
            this.contents.riqid = "";
            this.contents.carbo = "";
            this.contents.calorie = "";
            this.error_flg = false;
            this.errors = [];
        }
    }
}
</script>
app.js

Vue.component('eating-input-dialog-component', require('./components/Eating/EatingInputDialogComponent.vue'));
EatingDashboardComponent.vue

<template>
    <div>
        <div class="dashboard">
            <div class="chart">
                <canvas id="eating"></canvas>
            </div>
            <div class="command">
                <ul>
                    <li><a @click="onClickPrev">prev</a></li>
                    <li><a @click="onClickNext">next</a></li>
                </ul>
                <ul>
                    <li><a @click="onClickInput">クイック入力</a></li>
                    <li><a href="">詳細</a></li>
                </ul>
            </div>
        </div>
        <eating-input-dialog-component :show="showInputDialogContent" @update="invokeUpdateList"></eating-input-dialog-component>
    </div>
</template>

<script>
export default {
    data() {
        return {
            showInputDialogContent: false,
        };
    },
    methods: {
        onClickInput: function() {
            this.showInputDialogContent = true;
        },
        invokeUpdateList: function() {
            //this.graphUpdate(this.graphNum);
        },
    }
}
</script>

【ラズパイ】pythonプログラムをサービスで実行する

ラズパイZeroで作成したpythonプログラムをサービスに登録して、起動と同時に実行するように設定します。

以下のファイルを作成

pimonitor.service

[Unit]
Description=PIMonitor
After=syslog.target

[Service]
Type=simple
WorkingDirectory=/opt/pimonitor
ExecStart=/usr/bin/python3 main.py
TimeoutStopSec=5
StandardOutput=null

[Install]
WantedBy = multi-user.target

このファイルを/etc/systemd/system/配下にコピー

$ cp pimonitor.service /etc/systemd/system

※ /opt/pimonitor配下にソースファイル全て揃っている前提。

パーミッションの設定でrootでも実行できようにしておく

$ chmod 777 *

サービス開始

$ sudo systemctl start pimonitor.service

サービス登録

$ sudo systemctl enable pimonitor.service

【ダイエット】実践していることその3、ダイエットのためにお金をケチらない

その1についてはこちら。

【ダイエット】実践していることその1、体重計を買うべし

その2についてはこちら。

多少波がありますが、今、体重が減少傾向にあります。

今日明日頑張ればもっと体重落ちそう。

ダイエットを本気で取り組もうと思っているならば、あえて、高いコストをかけるというのも1つの手段ダと思います。

自分の場合は、トレーニングウェアに1万円のスポーツブランド(デサント)を購入しましたし、

トラッカーには2万円のFitbit Versa 2を購入。

体重測定には1万円のFitbit Aria2を使用していますし、

ランニングでは2.6万円のソニー WF-SP800Nを購入しました。

SAVASのデカイ袋のプロテインをほぼ毎日飲んでいます。

なぜ高い物を選択するのかというと、

ダイエット・トレーニングの効率を高めるという意味もありますが、

ダイエットを諦めるハードルを下げないためでもあります。

例えば、こんな経験は無いですか?

近所に安くていつでも使えるトレーニングジムが出来たと聞いて、会員になったものの、結局月に1回しか通ってない。

いつでも通えると思ったら明日でいいやと思ったり、結局めんどくさいと思ったり。

そんな状態のまま数ヶ月、無駄にジムの月額使用料を支払っている。

(まさしく過去の自分です。)

後々考えれば、こんなことにお金を使わずに、お金はかかるけど完全予約制の専属トレーナー付きのジムに通った方が、遙かに効率的だと思いませんか?

完全予約制ですから必ずジムに通わなければなりませんし、トレーナーがきちんとトレーニングを指導してくれます。

ここまでやったら成果が出ないと、もったいないじゃ無いですか。

これは一つの例でしたが、

結局、安いコストしかかけていないと、止めようと思ったら簡単に止めることが出来てしまいます。

しかし、高いコストをかけることで、「ここまでお金をかけたんだから成果を出さないともったいない。」という考えが出てくると思うんです。

つまり、ダイエットを諦めるハードルが全然違ってくるんです。

ハードルを高くすることは継続に繋がります。

本気でダイエットをしたいと考えているのならば、安物で揃えてそれで成果が出ればラッキー、という考えでは無くて、高い金をかけてるんだから絶対成果を出してやる!という考えじゃないと無理だと思います。

まさしくそれがダイエットに対する本気度だと思いますよ。

【北海道大戦】ランダムで隣接する都市を選択する

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/HokkaidoWar

今回はバトルを仕掛ける市町村を選択する処理を実装します。

自分のターンが回ってきた市町村から、隣接する市町村をランダムで選択し、攻撃を仕掛ける、という感じにしたいと思います。

ただし、何もしない(攻撃を仕掛けない)ケースもあるものとします。

さらに、攻撃側の市町村と防御側の市町村が分かるように色分けしましょうか。

    class City
    {

        public void PaintAttackColor()
        {
            var color = new asd.Color(255, 0, 0);
            foreach(var m in _maps)
            {
                m.SetColor(color);
            }
        }

        public void PaintDeffenceColor()
        {
            var color = new asd.Color(0, 0, 255);
            foreach (var m in _maps)
            {
                m.SetColor(color);
            }
        }

        public void ClearPaint()
        {
            foreach (var m in _maps)
            {
                m.SetColor(_color);
            }
        }
    class Battle
    {
        public void NextTurn()
        {
            if(prevAttack != null)
            {
                prevAttack.ClearPaint();
            }
            if(prevDeffece != null)
            {
                prevDeffece.ClearPaint();
            }

            var targets = _cities[cityCnt].GetLinkedCities();
            var r = Singleton.GetRandom();
            int targetIdx = r.Next(0, targets.Count + 1);
            prevAttack = _cities[cityCnt];
            prevAttack.PaintAttackColor();

            var info = Singleton.GetGameProcessInfomation();
            if(targetIdx >= targets.Count)
            {
                info.ShowText(prevAttack.GetPosition(), string.Format("{0} turn {1} / {2} {3}",
                    turn, cityCnt + 1, _cities.Count, prevAttack.Name));
            }
            else
            {
                prevDeffece = targets[targetIdx];
                prevDeffece.PaintDeffenceColor();
                info.ShowText(prevAttack.GetPosition(), string.Format("{0} turn {1} / {2} {3}\r\ntarget {4}",
                    turn, cityCnt + 1, _cities.Count, prevAttack.Name, prevDeffece.Name));
            }

            cityCnt++;
            if(cityCnt >= _cities.Count)
            {
                _cities = cityRandomReplace(_cities);
                cityCnt = 0;
                turn++;
            }
        }

隣接する都市を取得する処理は今までに作成しているので、メソッド1つで取り出せます。

その中から乱数で1つ都市を選択します。

ただし、何もしないターンもあるので、乱数の範囲を大きめにとって、配列より大きければ、何もしない、と扱います。

【ラズパイ】【いろいろ計測モニター】実際に組んでみる。

今日は9時間頑張りました。

実際にこの回路を組んでみました。

材料はこちらの記事にあります。

結果はこうなりました。

挫けた。

そもそも、

このラズパイZero用の基板に全部盛り込もうとしたのが間違い。

かなり難易度の高いはんだ付け作業になりました。

また、穴と穴が繋がっていない(ユニバーサル基板とはそういうもの)ので、その線をつなぐのも苦労しました。

さらに、


GLCD側のピッチ幅がラズパイZero側の基板より小さい事が発覚。

これがさらにはんだ付けの難易度を上げました。

はんだの熱で基板と部品が若干溶けてました。

このままじゃ悔しいので、ブレッドボードに回路を作り直して、ラズパイZeroで動かしました。

今回はこれで勘弁してください。

9時間頑張ったんだよ・・・

でもラズパイZeroで動かしているので、長時間稼働していても全然暑くないです。

でも性能は明らかに劣っているからモッサリしているけどね。

損傷して使い物にならなくなってしまいました。

残念ながらゴミ箱行きです。

【LARAVEL】【ダイエット支援】ダッシュボードに食事管理を追加する

前回までの状況はこちら

最新ソースファイルはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

ダッシュボード画面に、

この画面の追加します。

ベースは体重管理のものを流用できるので、さくっと作成しました。

EatingDashboardComponent.vue

<template>
    <div>
        <div class="dashboard">
            <div class="chart">
                <canvas id="eating"></canvas>
            </div>
            <div class="command">
                <ul>
                    <li><a @click="onClickPrev">prev</a></li>
                    <li><a @click="onClickNext">next</a></li>
                </ul>
                <ul>
                    <li><a @click="onClickInput">クイック入力</a></li>
                    <li><a href="">詳細</a></li>
                </ul>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
        };
    },
    created: function() {
    },
    mounted: function() {
    },
    methods: {
        onClickNext: function() {
        },
        onClickPrev: function() {
        },
        onClickInput: function() {
        },
    }
}
</script>
app.js

Vue.component('eating-dashboard-component', require('./components/Eating/EatingDashboardComponent.vue'));
home.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Dashboard</div>

                <div class="panel-body">
                    @if (session('status'))
                        <div class="alert alert-success">
                            {{ session('status') }}
                        </div>
                    @endif

                    <weight-dashboard-component></weight-dashboard-component>
                    <p></p>
                    <eating-dashboard-component></eating-dashboard-component>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

【ラズパイ】【いろいろ計測モニター】

どうせならきちんとして使える物を作りたい。

前回まではラズパイ4(2GB)を使用しましたが、これって、ファンを使わないと発熱がやばいらしいですね。

なので、消費電力が少なくて、発熱も少ないラズパイZERO HWを買いました。

使用する部品も買いました。

MicroUSBのACアダプター

MicroSDカード(16GB)

8GBでも十分だったんだけどね。

これらは今まで使用していた部品と同じです。

ラズパイZero用の基板です。

これにピンヘッダを取り付けて、基板と本体を取り外しできるようにします。

スイッチに使用する抵抗とダイオード。

(たぶん)同じ物を購入しました。

それらをつなぐジャンパ線です。

こんな感じで回路を組もうと思ってます。

結構ごちゃごちゃしてる。

まぁ、ピンの位置とか実際の位置に合わせて書いているので仕方が無い。

問題はスイッチが正しく動くかどうか。

前回は12個のスイッチでしたが、今回は1個のスイッチを使います。それに合わせて同じような回路を組んでいます。

ちゃんと機能するか、ブレッドボードに簡単に組んでみました。

上手くいけば、スイッチ押下時にインプット信号がHIGH→LOWになるはずです。

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(21, GPIO.IN)
swState = 0

try:
    while True:
        if GPIO.input(21) == 0 and swState == 0:
            time.sleep(0.05)
            if GPIO.input(21) == 0:
                print("ON")
                swState = 1
        elif GPIO.input(21) == 1 and swState == 1:
            print("OFF")
            swState = 0
        time.sleep(0.005)

except KeyboardInterrupt:
    GPIO.cleanup()
$ python3 test.py 
ON
OFF
ON
OFF
ON
OFF
ON
OFF
ON
OFF

うん、うまく動いているようです。

じゃあ、制作開始といきますか。

【料理】【リュウジのバズレシピ】絶品鶏チャーシューを作ってみた

意外と味が浸みるもんだね。

こちらのレシピ動画を参考にしました。

レンチンだけで出来てしまって、しかも美味しいというのがスゴイ。

しっかり味が付いてるし、火も通っているし、何よりお酒がすすむ。

動画の中では600Wの電子レンジを使用していますが、うちの電子レンジは500Wなので、動画よりも少しレンチン時間を長めにしています。

最初に5分30秒、裏返して3分ぐらい。

レンチン中も良い香りがしてお腹が空きます。

そして、冷蔵庫で寝かしたらさらに味が浸みて美味いと言うことなので、約10時間冷蔵庫で寝かしました。

いや、美味かった。

けどレンチンしたての熱々でも食べてみたいな。

いろいろアレンジ試してみたいと思います。

【C#】【ピクロス】【ALTSEED】解析パターン15

前回までの状況はこちら。

最新ソースはこちら。(gitHub)

https://github.com/takishita2nd/Picross

次はこちらの問題を解いてみます。

実行結果はこちら

惜しい。

多分、次やらなくちゃ行けないのはここだろうな。

ここは2,2,5とすでに塗られているので、空いている空白はマスクで確定されます。

ちょっと解析パターン11と似ていますが、こんなコードを組んでみました。

        // 解析パターンその15
        // 数字と空いているマスを照合して塗る
        private void pattern15()
        {
            // Row
            pattern15Row();
            // Col
            pattern15Col();
        }

        private void pattern15Row()
        {
            int row = 0;
            foreach (var rowlist in rowNumbers)
            {
                if (rowlist.IsAnalyzed())
                {
                    row++;
                    continue;
                }

                // 有効な数字を取り出す
                List<AnalyzeData> aData = new List<AnalyzeData>();
                foreach(var data in rowlist.AnalyzeDatas)
                {
                    if (data.IsAnalyzed())
                    {
                        continue;
                    }
                    aData.Add(data);
                }

                // 対象となるマスを抽出する
                List<List<BitmapData>> bitmapLists = extractTargetBitmapListsCol(row);
                bitmapLists.Reverse();

                // 数字とマスを照合する
                if (bitmapLists.Count != aData.Count)
                {
                    row++;
                    continue;
                }

                for(int i = 0; i < aData.Count; i++)
                {
                    int count = 0;
                    // 塗られているマスを数える
                    foreach (var b in bitmapLists[i])
                    {
                        if (b.IsPainted())
                        {
                            count++;
                        }
                    }
                    // 塗られているマスと数字が一定している場合は空きマスをマスクする
                    if(aData[i].Value == count)
                    {
                        foreach(var b in bitmapLists[i])
                        {
                            if(b.IsValid() == false)
                            {
                                b.Mask();
                            }
                        }
                    }
                }
                row++;
            }
        }

        private void pattern15Col()
        {
            int col = 0;
            foreach (var collist in colNumbers)
            {
                if (collist.IsAnalyzed())
                {
                    col++;
                    continue;
                }

                // 有効な数字を取り出す
                List<AnalyzeData> aData = new List<AnalyzeData>();
                foreach (var data in collist.AnalyzeDatas)
                {
                    if (data.IsAnalyzed())
                    {
                        continue;
                    }
                    aData.Add(data);
                }

                // 対象となるマスを抽出する
                List<List<BitmapData>> bitmapLists = extractTargetBitmapListsRow(col);
                bitmapLists.Reverse();

                // 数字とマスを照合する
                if (bitmapLists.Count != aData.Count)
                {
                    col++;
                    continue;
                }

                for (int i = 0; i < aData.Count; i++)
                {
                    int count = 0;
                    // 塗られているマスを数える
                    foreach (var b in bitmapLists[i])
                    {
                        if (b.IsPainted())
                        {
                            count++;
                        }
                    }
                    // 塗られているマスと数字が一定している場合は空きマスをマスクする
                    if (aData[i].Value == count)
                    {
                        foreach (var b in bitmapLists[i])
                        {
                            if (b.IsValid() == false)
                            {
                                b.Mask();
                            }
                        }
                    }
                }
                col++;
            }
        }

んー思った以上に進んでいないぞ。

少々時間がかかりそうです。

もう少し調べてみます。

自分、ぼっちですが何か?