RaspberryPiをリモコンにしてエアコンをON/OFF

# 概要
我が家のエアコンは古くて、温度設定してもまともに設定した温度を保つことができません。冷房をONにしておくとどんどん温度が下がってしまいます。赤外線リモコンは動作しますので、外側でON、OFFを制御するちょっとしたIoT機器を作ってみました。

Raspberry PI zeroの温度センサーで温度を測定し、エアコンをON,OFFを赤外線通信で行います。学習リモコンは、こちらを参照して作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58417/c955325b-eab3-8c62-b6ab-65ae37ca3800.png)

# 部品

- 温度センサー：[mcp9808](https://www.switch-science.com/catalog/1708/)
- 赤外線リモコン受信モジュール：[OSRB38C9AA](http://akizukidenshi.com/catalog/g/gI-04659/)
- 赤外線LED：[503IRC2E-2AC](https://www.marutsu.co.jp/pc/i/838649/)

# アルゴリズム

エアコンがONになっているか、OFFになっているかを保持しているFLAGを持っています。FLAG=0がエアコンがOFFの状態、FLAG=1がエアコンがONの状態を表しています。FLAG=0の場合、温度を測ってある温度（Tmax)以上ならエアコンをONにします、FLAG=1の場合、ある温度（Tmin)以下になったらエアコンを切ります。OFFからON、反対にOFFからONに状態が変化したとき、それぞれ３０分、エアコンが効いてくるのを待ちます。

最初、ある温度になったらエアコンをON、ある温度以下ならエアコンをOFFにするという簡単なプログラムでした。設定した温度の間際で、何度もエアコンONのリモコン操作を行ってしまい、エアコンが「ピー・ピー」とやかましいことにななってしまいました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58417/0f045bb0-8a8f-dec9-1867-4ab123a7645e.png" width="400">

そこでFLAGと待ち時間を取り込むことにしました。FLAG=1の時は、エアコンをOFFにする温度を目指して、温度がTmaxを超えてももう一度ONにすることはしません。また、ONにした後、30分は何もしないように変更してしまいました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58417/a3de7da2-b782-6ec6-05fa-4d0d50e7d426.png" width="400">

面倒なのは、寝ていて自分でがまんできなくてエアコンのリモコンをいじってしまうこと。手動でリモコンでエアコンを入れて（切って）しまうとFLAGと矛盾してしまいます。FLAG=0でエアコンをONにするタイミングを探しているのに、ほんとはエアコンはONになっていてどんどん温度が下がってしまい、OFFにするタイミングを探さないといけないとか。

そのために、探している方向と逆になった場合にFLAGを反転する仕組みを入れています。


![アルゴリズム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58417/10ddc8d3-cf4f-8cfa-b49c-90e4c0750405.png)

# 回路図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58417/f011924f-763d-cf21-6e74-41900eae0728.png)

## 実際の工作

あれこれと基板を使いまわしていますので、あまり参考にはならないと思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58417/69c6194d-a639-cea0-877b-8055a6f184b3.png" width="480">

# プログラム

プログラムはpythonで書いています。

## mcp9808のプログラム

smbusライブラリを利用します。smbusはI2Cとほとんど同じ規格とのことです。動作させてみると問題なく温度を測定することができています。

``` mcp9808.py
# -*- coding: utf-8 -*-
import smbus
from time import sleep

true    =1
false   =0

MCP9808_I2CADDR_DEFAULT        =0x18   # < I2C address
MCP9808_REG_CONFIG             =0x01   # < MCP9808 config register

MCP9808_REG_CONFIG_SHUTDOWN	   =0x0100 # < shutdown config
MCP9808_REG_CONFIG_CRITLOCKED  =0x0080 # < critical trip lock
MCP9808_REG_CONFIG_WINLOCKED   =0x0040 # < alarm window lock
MCP9808_REG_CONFIG_INTCLR      =0x0020 # < interrupt clear
MCP9808_REG_CONFIG_ALERTSTAT   =0x0010 # < alert output status
MCP9808_REG_CONFIG_ALERTCTRL   =0x0008 # < alert output control
MCP9808_REG_CONFIG_ALERTSEL    =0x0004 # < alert output select
MCP9808_REG_CONFIG_ALERTPOL    =0x0002 # < alert output polarity
MCP9808_REG_CONFIG_ALERTMODE   =0x0001 # < alert output mode

MCP9808_REG_UPPER_TEMP         =0x02   # < upper alert boundary
MCP9808_REG_LOWER_TEMP         =0x03   # < lower alert boundery
MCP9808_REG_CRIT_TEMP          =0x04   # < critical temperature
MCP9808_REG_AMBIENT_TEMP       =0x05   # < ambient temperature
MCP9808_REG_MANUF_ID           =0x06   # < manufacture ID
MCP9808_REG_DEVICE_ID          =0x07   # < device ID
MCP9808_REG_RESOLUTION         =0x08   # < resolutin

class mcp9808():
    def __init__(self, ):
        self.bus = smbus.SMBus(1)
        self.address_mcp9808 = MCP9808_I2CADDR_DEFAULT
        self.register_mcp9808 = MCP9808_REG_AMBIENT_TEMP
        while(self.mcp9808_init()==false):
            print("*")

    def mcp9808_init(self):
        word_data = self.bus.read_word_data(self.address_mcp9808, MCP9808_REG_MANUF_ID)
        print("MCP9808_REG_MANUF_ID=",word_data)
        if (word_data!=0x5400):
            return false;
        word_data = self.bus.read_word_data(self.address_mcp9808, MCP9808_REG_DEVICE_ID)
        print("MCP9808_REG_DEVICE_ID=",word_data)
        if (word_data != 0x0004):
            return false;
        self.bus.write_word_data(self.address_mcp9808, MCP9808_REG_CONFIG, 0)
        return true;

    def read_mcp9808(self):
        word_data = self.bus.read_word_data(self.address_mcp9808, self.register_mcp9808)
        word_data = ((word_data&0xFF00)>>8) + ((word_data&0x00FF)<<8)
        data = word_data & 0xfff
        temperature = data/16.0
        if(word_data&0x1000):
            temperature=temperature-256;
        return temperature

    def shutdown_wake(self,sw):
        conf_register = self.bus.read_word_data(self.address_mcp9808, MCP9808_REG_CONFIG)
        if (sw == true):
            conf_shutdown = conf_register | MCP9808_REG_CONFIG_SHUTDOWN
            self.bus.write_word_data(self.address_mcp9808, MCP9808_REG_CONFIG, conf_shutdown)
        if (sw == false):
            conf_shutdown = conf_register & ~MCP9808_REG_CONFIG_SHUTDOWN
            self.bus.write_word_data(self.address_mcp9808, MCP9808_REG_CONFIG, conf_shutdown)

    def read_temperature(self):
        self.shutdown_wake(false)
        sleep(0.25)
        inputValue = self.read_mcp9808()
        return inputValue
```

使う側では、以下のように温度を測定することができます。

```
from mcp9808 import *
mcp=mcp9808()
tmp=mcp.read_temperature()
print(tmp)
```