RaspberryPi + Django + Arduinoで部屋の電気をIoT化

# 目的
趣味で部屋をIoT化、もとい改造しています。
その内の一つとして、部屋の電気→スイッチをスマホから操作してみたくなりました。

ところが、部屋の電気のスイッチを直接いじるには、電気工事士の資格が必要になるため、誰でもモジュールを取り付けることでIoT化できるようなものを作る縛りゲーを自らに課しました。

#使ったもの・開発環境
PC(win10)
RaspberryPi 3 Model B+(NOOBS)
Arduino Nano (廉価版)
Pycharm Professional　2019.2(学生ライセンス)
ArduinoIDE
Python3.7.4(ラズパイ内)
Django 2.2.6(ラズパイ内)
サーボモータSG90

#構想
将来さらに改造することを考えると、ラズパイ1台ですべて制御するのは限度を感じたため、今回はラズパイを親機、arduinoを子機のように使うシステムを構想。Arduino nanoの廉価版はウルトラ安い。また、djangoで作るwebアプリは家の中で動作してくれさえすればいいので、wifi経由でラズパイのipにアクセスして使う。
**また今回は、「ちゃんと手動でも操作したい」という願いを考慮する。**
![lightiot_fig.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527252/1296de3c-ce4c-c5e1-7ff8-728997b84441.png)


#ローカルのウェブサイトを立てる
pycharmでコーディングしながら、ftp通信したラズパイにデプロイしてました。
中身は超基本なものと変わらない。テンプレートで作成したbuttonによって、on/offそれぞれ作ったviewsを呼び出し、viewsの中で別のfunction.pyのフラグを上げ下げする。

```python:polls/function.py
import RPi.GPIO as GPIO


def switch_on_off(state):
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(11, GPIO.OUT)
    GPIO.output(11, state)
```
```python:polls/views.py
from django.shortcuts import render, redirect
import RPi.GPIO as GPIO
from . import function

GPIO.cleanup()


def index(request):
    return render(request, 'pagetop.html')


def on(request):
    switch_state = True
    print(switch_state)
    function.switch_on_off(switch_state)
    return render(request, 'pagetop.html', {'State': 'On'})


def off(request):
    switch_state = False
    print(switch_state)
    function.switch_on_off(switch_state)
    return render(request, 'pagetop.html', {'State': 'Off'})
```
テンプレートはこんな感じ

```html:template/pagetop.html
<table border="1" cellpadding="0">
 <tr>
  <th colspan="2">
   部屋の電気IoT
  </th>
 </tr>
 <tr>
  <td colspan="2">
   電気スイッチの状態: {{ State }}
  </td>
 </tr>
 <tr>
  <td>
   <div class="switch">
    <a href="{% url 'on' %}">On</a>
   </div>
  </td>
  <td>
   <div class="switch">
    <a href="{% url 'off' %}">Off</a>
   </div>
  </td>
 </tr>
</table>
```
これで現在のスイッチの状態を表示して、かつ簡単にon/offを制御できた。

#Arduinoとハードウェア
##Arduino制御
Arduinoでは2つの事をしたい。
1. ラズパイから受け取ったon/offのフラグによってスイッチを制御
2. 手動用のスイッチが押されたらon/offを反転
コードが雑なのは整理してないからで、以下のように書いた。

```C
/// include the Servo library
#include <Servo.h>

Servo myServo;  // create a servo object

int angle;   // variable to hold the angle for the servo motor
bool switch1 = false;
bool switch0 = false;
const int ledpin = 5;
const int switchPin = 3;
int state,raspi_state,switch_state;
int d_state,d_r_state;
int raspi_onoff = 4;
int cycle = 0;

void actionServo(int);
int actionswitch(void);
int actionraspi(void);

void setup() {
  myServo.attach(9); // attaches the servo on pin 9 to the servo object
  Serial.begin(9600); // open a serial connection to your computer
  myServo.write(90);
  pinMode(ledpin,OUTPUT);
  pinMode(switchPin,INPUT);
  pinMode(raspi_onoff,INPUT);
  digitalWrite(ledpin,HIGH);
  delay(1000);
  digitalWrite(ledpin,LOW);
  state = 1;
  d_state = 1;
  d_r_state = 1;
}

void loop() {
  state = digitalRead(switchPin);
  raspi_state = digitalRead(raspi_onoff);
  
  if(switch_state == 0){
    if(actionswitch()||actionraspi() == 1){
      actionServo(1);
      switch_state = 1;
    }
  }else{
    if(actionswitch()||actionraspi() == 2){
      actionServo(0);
      switch_state = 0;
    }
  }  
  
  Serial.print("raspi: ");
  Serial.println(raspi_state);
  delay(10);
  d_state = state;
  d_r_state = raspi_state;
  
}

void actionServo(int act){
  if(act){Serial.println("ON");}else{Serial.println("OFF");}
  int angle;
  if(act){angle=105;}else{angle=75;}
  myServo.write(angle);
  digitalWrite(ledpin,HIGH);
  delay(500);
  myServo.write(90);
  digitalWrite(ledpin,LOW);
  delay(500);
}

int actionswitch(void){
  if(d_state == 0){
    if(state == 1){
      return 1;
    }
  }
  if(d_state == 1){
    if(state == 0){
      return 1;
    }
  }
  return 0;
}

int actionraspi(void){
  if(d_r_state == 0){
    if(raspi_state == 1){
      return 1;
    }
  }
  if(d_r_state == 1){
    if(raspi_state == 0){
      return 2;
    }
  }
  return 0;
}
```
1．2．の変化を読み取るための関数と、モータを作動するための関数を組み合わせて完成。

##ハードウェア
今回は、「誰でも取り付けるだけで使用できるモジュール」をコンセプトにし、スイッチの電気系統を直接いじらずオンオフを制御するため、サーボモータでスイッチを物理的に押すことで制御した(アナログ感)
ハードは3Dプリンタで作成して、あとはパーツをはめるだけ。パーツは以下の通り。
1. サーボモータ
2. パナソニックとかが売ってる部屋のスイッチ
3. 制御ユニット(Arduino+自作電源回路)

fusion360とかで作って。。。
<img width="319" alt="light_fusion.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527252/58b46048-c707-8966-a976-a0ef11190624.png">
こうじゃ
<img width="50%" alt="S__77389826.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527252/70534acc-74a0-3ad0-465d-8606d54c8a56.jpeg">
<img width="50%" alt="S__77389828.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527252/02354c50-cbd0-efb7-c4a7-0d72bae0b3e3.jpeg">
これを今あるスイッチにカポッと取り付けます。

#完成！
こうして、部屋の電気を手動でもスマホからでもつけたり消したりできるモジュールが完成！gifでどうぞ。
![ezgif-6-cab5346c22c6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527252/61ecf629-93b0-8a14-d3a4-f13fbd51c065.gif)