nemの灯~Raspberrypi,Pythonで作るクリスマスイルミネーション~

#はじめに
クリスマスも近いので、
nemのトランザクション量に合わせて明るくなるイルミネーションを作りました。

明るさは、
　・2秒ごとに暗く(デューティ比-1%)
　・nemブロック生成時のトランザクション量分明るく(デューティ比＋x%)
なります。

nemのトランザクション量に左右される光なので、「nemの灯」と名前を付けました。

![IMG_5828.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256819/d035fb85-66e9-889d-167b-2879096368e6.jpeg)

本記事を最後まで実施頂くことで、下記2つが身につくことでしょう。
・電子工作界の「Hello world」ことLチカの技術
・nem界の「Hello world」ことトランザクション確認の技術


# 必要な物（値段は一例）

・Rasberry Pi Zero WH(他のラズパイでも可です)
　　1848円(スイッチサイエンス)
　　https://www.switch-science.com/catalog/3646/
・ジャンパワイヤ（メス～ワニ口）※100均のワニ口加工したら100円
　　955円(スイッチサイエンス)
　　https://www.switch-science.com/catalog/5534/
・マイクロSDカード 16GB
　　820円(amazon)
・ラズパイにssh接続するためのPC(Windows,Mac,Linux等)
・イルミネーションと箱
　　100円×2(ダイソー)
　※お手持ちのイルミネーション機器(単三2本ほどで動くもの)でも可

#０．ラズパイを準備しよう！

Raspberrypi（ラズパイ）とは、英ラズベリーパイ財団が開発した超小型のシングルボードコンピューターです。
ラズパイの種類は多々ありますが、今回はより小さく安いRaspberrypi zeroWHという種類を
使って解説していきます。

まずはラズパイを持っていない方は買いましょう。
amazonなどでは、結構定価より高くなっていることが多いので、
スイッチサイエンスさん等で買うことをお勧めします。

ラズパイの準備については、色々記事記事があると思うので、こちらでは割愛します。
https://qiita.com/RyoheiTomiyama/items/4c25f146264521cf6446

#１．ラズパイでLチカしてみよう！

まずは、プログラミングでいうところの『Hello World!』である
Lチカ(LEDを点灯させる)をやってみましょう。

##GPIO用のライブラリをインストールする

```
$ sudo apt install python3-rpi.gpio
```

###Lチカプログラムの作成

```python:gpio.py
#!/usr/bin/python3
 
import RPi.GPIO as GPIO
import time
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
try:
        while True:
                GPIO.output(18, True)
                time.sleep(0.1)
                GPIO.output(18, False)
                time.sleep(0.1)
 
except KeyboardInterrupt:
        pass
 
GPIO.cleanup()

```

###ラズパイの配線
ラズパイのGPIO18ピンとお手持ちのイルミネーションを繋げましょう。
![Untitled Sketch_ブレッドボード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256819/c059dd42-8c14-bfc8-9dcc-08a16d362601.jpeg)　![IMG_5838.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256819/e07f359b-a248-086d-741b-e46ef57b91a5.jpeg)

###Lチカプログラムの実行
```
$ python3 gpio.py
```
0.1秒に1回ずつ、LEDのオンとオフを繰り返すはずです。
プログラムはCtrl + C で停止させます。


#２．ラズパイでPWM制御してみよう！
PWMとはPulse Width Modulationの略でパルス幅変調を用いた制御のことです。
ラズパイはデジタルな制御(1か0か、今回の場合3.3Vか0Vか)しか出力出来ません。

そこで、非常に短い間隔でオンオフを繰り替えし、オンの時間とオフの時間の比(デューティ比)を
調整することで、LEDの光度やモーターの速さを調整することが出来ます。
例えば、1秒間にオンオフを数百回繰り返した場合、人が見た場合50%のオンの光として認識されます。

下記ファイルを作成し、実行してみましょう。

```python:pwm.py
#!/usr/bin/python3
 
import RPi.GPIO as GPIO
import time
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT) #18ピンを利用

Duty = 100

try:
        while True:
                pwm = GPIO.PWM(18, 100000) #PWM出力(18ピン,1000Hz)
                pwm.start(0)

                # LED点灯
                for i in range(Duty):
                        pwm.ChangeDutyCycle(i)
                        time.sleep(0.1)

                # LED消灯
                for i in range(Duty):
                        pwm.ChangeDutyCycle(Duty - i)
                        time.sleep(0.1)
                pwm.stop()

except KeyboardInterrupt:
        pass
 
GPIO.cleanup()


```

PWM制御は、上記の通りGPIOライブラリでも使えるみたいですが、ソフトウェアで制御するためか
他の処理の影響を受けてしまい、安定しません。

そこでハードウェア側でPWM制御可能なwiringpiを使って同じことをしたいと思います。

##wiringpi用のライブラリをインストールする

```
$ sudo pip3 install wiringpi
```

###プログラムの作成

```python:wiringpi_pwm.py
#!/usr/bin/env python3
# coding: utf-8

import wiringpi
import time

pwm_pin = 18
interval = 1

range2 = 1024
hz = 1 / ( interval * 0.001 )
clock = int( 18750 / hz )

# 初期設定
wiringpi.wiringPiSetupGpio()
wiringpi.pinMode( pwm_pin, wiringpi.GPIO.PWM_OUTPUT )
wiringpi.pwmSetMode( wiringpi.GPIO.PWM_MODE_MS )
wiringpi.pwmSetClock( clock )

# LED点灯
for i in range(101):
    duty = int(i / 100 * range2)
    print("i = ", i, "clock = ", clock, " duty=", duty )
    wiringpi.pwmWrite( pwm_pin, duty )
    time.sleep(0.05)

# LED消灯
for i in range(101):
    duty = int((100 - i) / 100 * range2)
    print("i = ", i, "clock = ", clock, " duty=", duty )
    wiringpi.pwmWrite( pwm_pin, duty )
    time.sleep(0.05)
```



###PWMプログラムの実行
```
$ python3 wiringpi_pwm.py
```

wiringpiを用いた方がかなりキレイにLEDが光ったと思います。


#３．NEMトランザクションを検知してみよう！
では、お待ちかね？のNEMトランザクションの検知をしてみましょう。

指定したNEMアドレスに着金があった場合にLEDが光るようにします。
なお、上記で作成した「wiringpi_pwm.py」を呼び出しているので、
「wiringpi_pwm.py」と同じ階層に配置頂く必要があります

###プログラムの作成

```python:address_transaction.py
import requests
import json
from time import sleep
import random
import os

node  = random.choice(("http://alice2.nem.ninja:7890","http://alice3.nem.ninja:7890",\
    "http://alice4.nem.ninja:7890","http://alice5.nem.ninja:7890",\
    "http://alice6.nem.ninja:7890","http://alice7.nem.ninja:7890"))
print(node)

api = '/account/unconfirmedTransactions'
parameter = 'address=NB3KO7I5RVBON2MNAO5K4STBCQROG5LUJHQB3EZM' 
# 一例としてnemlogのアドレスを記載しています。各自監視したいアドレスに変更下さい。

url = str(node + api + '?' + parameter)

nemTimeStamp = 0

while True:

    try:
        r = requests.get(url, timeout=(6.0, 7.5)).json()
    except:
        print("node is: ", node)
        node  = random.choice(("http://alice2.nem.ninja:7890","http://alice3.nem.ninja:7890",\
            "http://alice4.nem.ninja:7890","http://alice5.nem.ninja:7890",\
            "http://alice6.nem.ninja:7890","http://alice7.nem.ninja:7890"))
        print("node change: ", node)
        continue

    sleep(5)
    try:
        if not r['data']:
            print('none')
            continue
        elif nemTimeStamp != r['data'][0]['transaction']['timeStamp']:
            os.system('python3 ./wiringpi_pwm.py')
            print('トランザクションが' + str(len(r['data'])) + '個もあるって素敵やん')
            nemTimeStamp = r['data'][0]['transaction']['timeStamp']

    except:
        print('トランザクションが0個は泣けるやん')
        sleep(5)
        continue

```

###着金確認プログラムの実行
```
$ python3 address_transaction.py
```

#４．灯せ！nemの灯！

最後に、nemの灯のプログラムを紹介します。
最初は100%の明るさで光っており、
　・2秒に1%ずつ暗くなっていく
　・nemで生成されたブロックごとにトランザクション量を測り、その%分だけ明るくなる
というものです。

この灯を見ることで、今のnemの元気さ(トランザクション量の多さ)が直感的に分かるようになっています。

###プログラムの作成

```python:nemFire.py
import requests
import json
from time import sleep
import random
import wiringpi

### 初期設定 ###
# wiringpi
pwm_pin = 18
interval = 1

range2 = 1024
hz = 1 / ( interval * 0.001 )
clock = int( 18750 / hz )
wiringpi.wiringPiSetupGpio()
wiringpi.pinMode( pwm_pin, wiringpi.GPIO.PWM_OUTPUT )
wiringpi.pwmSetMode( wiringpi.GPIO.PWM_MODE_MS )
wiringpi.pwmSetClock( clock )
Duty = 100

# nem
node  = random.choice(("http://alice2.nem.ninja:7890","http://alice3.nem.ninja:7890",\
    "http://alice4.nem.ninja:7890","http://alice5.nem.ninja:7890",\
    "http://alice6.nem.ninja:7890","http://alice7.nem.ninja:7890"))
print("node first select: ", node)

api = '/chain/last-block'
url = str(node + api)

nemTimeStamp = 0
nemTimeStamp2 = 0

sleep_distance = 3

def up_pwm(duty, upcount):
    for i in range(upcount):
        wiringpi.pwmWrite( pwm_pin, int((duty + i) / 100 * range2) )
        print("up_pwm: ", (duty + i))
        sleep(sleep_distance / 10)

def down_pwm(duty, downcount=1):
    if duty <= 0:
#        wiringpi.pwmWrite( pwm_pin, 0 )
        sleep(sleep_distance)
        return

    for i in range(downcount * 10):
        wiringpi.pwmWrite( pwm_pin, int((duty - i / 10) / 100 * range2) )
        print("down_pwm: ", (duty - i / 10),"duty_turm: ", int((duty - i / 10) / 100 * range2))
        sleep(sleep_distance / 10)


try:
    while True:
        try:
            r = requests.get(url, timeout=(6.0, 7.5)).json()
        except:
            print("node is: ", node)
            node  = random.choice(("http://alice2.nem.ninja:7890","http://alice3.nem.ninja:7890",\
                "http://alice4.nem.ninja:7890","http://alice5.nem.ninja:7890",\
                "http://alice6.nem.ninja:7890","http://alice7.nem.ninja:7890"))
            print("node change: ", node)
            continue

        try:
            nemTimeStamp2 = r['transactions'][0]['timeStamp']

            if nemTimeStamp != nemTimeStamp2:
                print('トランザクションが' + str(len(r['transactions'])) + '個もあるって素敵やん')
                nemTimeStamp = nemTimeStamp2
                up_pwm(Duty,len(r['transactions']))
                Duty = Duty + len(r['transactions'])
                continue

        except:
            print('トランザクションが0個は泣けるやん')

        down_pwm(Duty)
        Duty = Duty - 1

        if Duty > 100:
                Duty = 100
        elif Duty < 0:
                Duty = 0
        
        print(Duty) 

except KeyboardInterrupt:
    pass
```

###nemの灯の実行
```
$ python3 nemFire.py
```
#所感

NEM好きの方はトランザクションが生まれる？ことに喜びを覚えている方が多い印象なので、
トランザクションを肌で感じれるようになればと思い、記事を書きました。
非エンジニアの方や電子工作未経験者の中から一人でも多くラズパイやプログラムに興味を持って頂けたら
マジガチ幸いです。

後半から解説とかが雑になりましたが、また機会があれば記事を出すようにします。
初めてのQiita記事で多々お見苦しい点もあったかと思いますが、大目に見てやってください。

アウトプットをすると自分の中でも整理出来て良いですね。