r45635 / HVAC-IR-Control

Ir Send - Updated for HVAC Mitsubishi & Panasonic IR
GNU General Public License v3.0
246 stars 89 forks source link

Not an issue as such, how to use on Raspi.. #20

Open 35nine opened 6 years ago

35nine commented 6 years ago

Hi. Am banging my head on a wall here, have attempted to use the python port but no ir activity seen from ir led used. I have pigpio installed, have used the pip install command from the readme and then am lost, I admit not to know how to use this within python. I have run the mits demo code, it throws up no errors as such, just no ir light emitted. IR led is known to be fine, lirc commands all fine. If anyone can offer some extra guidance how to use, would be fantastic. Thanks

Ericmas001 commented 6 years ago

Hi ! I personnally use it everyday with a rpi-zero-w with Minibian installed.

The important thing is: When you use "hvac = Mitsubishi(23, LogLevel.ErrorsOnly)", 23 is the GPIO number, not the PIN number My IR led is on GPIO 23 (Pin 16). untitled

I will give you more info than you need, so you can reproduce something close to my setup. This is my setup: https://github.com/Ericmas001/pi-adventures/blob/master/general/minibian_initial_setup.md

Then I installed:

sudo apt-get install git -y
sudo apt-get install python python-dev python-pip python-rpi.gpio pigpio -y
sudo pip install git+https://github.com/Ericmas001/HVAC-IR-Control
sudo pip install pigpio
sudo pip install flask

I use flask and a little webservice to control it, but that is not madatory. My IR led is on GPIO 23 (Pin 16).

app.py

#!/usr/bin/python

import logging 
from logging.handlers import RotatingFileHandler
from datetime import datetime, time
from flask import Flask, request, jsonify
from flask.json import JSONEncoder
import handler

class CustomJSONEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.isoformat()
        if isinstance(obj, time):
            return obj.isoformat()

        return obj.__dict__

class MyFlask(Flask):
    def make_response(self, rv):
        if hasattr(rv, 'response') and rv.response is None:
            return super(MyFlask, self).make_response(rv)
        if hasattr(rv, 'new_url') and rv.new_url is not None:
            return super(MyFlask, self).make_response(rv)
        return super(MyFlask, self).make_response(jsonify(rv))

app = MyFlask(__name__)
app.json_encoder = CustomJSONEncoder

@app.route('/config/', methods=['GET'])
def list_config():
    return handler.list_config(app)

@app.route('/hvac/off/', methods=['GET'])
def power_off():
    return handler.power_off(app)

@app.route('/hvac/on/', methods=['GET'])
def power_on():
    return handler.send_last_command(app)

@app.route('/hvac/command/', methods=['POST'])
def send_command():
    return handler.send_command(app, request.json)

@app.route('/last/command/', methods=['GET'])
def last_command():
    return handler.last_command(app)

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=4242)

handler.py

#!/usr/bin/python
from hvac_ircontrol.ir_sender import LogLevel
from hvac_ircontrol.mitsubishi import Mitsubishi, ClimateMode, FanMode, VanneVerticalMode, VanneHorizontalMode, ISeeMode, AreaMode, PowerfulMode, Constants
from models import *
import inspect
import json
from collections import namedtuple
import datetime
import traceback
import os

path = "/hvac/last_config.json"

def list_config(app):
    res = AvailableCommands()
    res.climate_modes = __list_attributes(ClimateMode)
    res.isee_modes = __list_attributes(ISeeMode)
    res.powerful_modes = __list_attributes(PowerfulMode)
    res.vanne_horizontal_modes = __list_attributes(VanneHorizontalMode)
    res.fan_modes = __list_attributes(FanMode)
    res.vanne_vertical_modes = __list_attributes(VanneVerticalMode)
    res.area_modes = __list_attributes(AreaMode)
    res.min_temp = Constants.MinTemp
    res.max_temp = Constants.MaxTemp
    return res

def power_off(app):
    hvac = Mitsubishi(23, LogLevel.ErrorsOnly)
    hvac.power_off()
    return "It was powered OFF"

def last_command(app):
    command = HvacCommand()
    if os.path.isfile(path):
        with open(path, 'r') as content_file:
            data = json.loads(content_file.read())
            command.from_json(data)
    return command

def send_command(app, data):
    command = HvacCommand()
    command.from_json(data)
    return __send_command(app, command)

def send_last_command(app):
    return __send_command(app, last_command(app))

def __send_command(app, command):
    try:
        hvac = Mitsubishi(23, LogLevel.Minimal)
        args = dict(
            climate_mode=__get_value(ClimateMode, command.climate_mode),
            temperature=command.temperature,
            fan_mode=__get_value(FanMode, command.fan_mode),
            vanne_vertical_mode=__get_value(VanneVerticalMode, command.vanne_vertical_mode),
            vanne_horizontal_mode=__get_value(VanneHorizontalMode, command.vanne_horizontal_mode),
            isee_mode=__get_value(ISeeMode, command.isee_mode),
            area_mode=__get_value(AreaMode, command.area_mode),
            start_time = __get_time_value(command.start_time),
            end_time = __get_time_value(command.end_time),
            powerful=__get_value(PowerfulMode, command.powerful_mode))
        hvac.send_command(**args)

        cfg = open(path, "w")
        cfg.write(command.to_json())
        return HvacCommandResponse(True,command,args)
    except:
        app.logger.error("There was an error: {0}".format(traceback.format_exc()))
        return HvacCommandResponse(False,data,"There was an error: {0}".format(traceback.format_exc()))

def __list_attributes(my_type):
    return [a[0] for a in inspect.getmembers(my_type, lambda c:not(inspect.isroutine(c))) if not a[0].startswith('_')]

def __get_value(my_type, my_value):
    return [a[1] for a in inspect.getmembers(my_type, lambda c:not(inspect.isroutine(c))) if a[0] == my_value][0]

def __get_time_value(my_value):
    if my_value is None or my_value < 0 or my_value >= 24:
        return None

    return datetime.time(int(my_value)//1, int((my_value*100)%100))

models.py

import json

class AvailableCommands:
    def __init__(self):
        self.climate_modes = []
        self.isee_modes = []
        self.powerful_modes = []
        self.vanne_horizontal_modes = []
        self.fan_modes = []
        self.vanne_vertical_modes = []
        self.area_modes = []
        self.min_temp = -1
        self.max_temp = -1

class HvacCommandResponse:
    def __init__(self, success, command, decoded):
        self.success = success
        self.command = command
        self.decoded_command = decoded

class HvacCommand:
    def __init__(self):
        self.climate_mode = "Cold"
        self.isee_mode = "ISeeOn"
        self.powerful_mode = "PowerfulOff"
        self.vanne_horizontal_mode = "NotSet"
        self.fan_mode = "Auto"
        self.vanne_vertical_mode = "Auto"
        self.area_mode = "NotSet"
        self.temperature = 21
        self.start_time = None
        self.end_time = None

    def from_json(self, data):
        self.climate_mode = data["climate_mode"]
        self.isee_mode = data["isee_mode"]
        self.powerful_mode = data["powerful_mode"]
        self.vanne_horizontal_mode = data["vanne_horizontal_mode"]
        self.fan_mode = data["fan_mode"]
        self.vanne_vertical_mode = data["vanne_vertical_mode"]
        self.area_mode = data["area_mode"]
        self.temperature = data["temperature"]
        self.start_time = data["start_time"]
        self.end_time = data["end_time"]

    def to_json(self):
        return json.dumps(self.__dict__, sort_keys=True, indent=4, separators=(',', ': '))

and some communication examples:

I/REQUEST: http://localhost:4242/hvac/off/
I/METHOD: GET
I/RESPONSE: "It was powered OFF"
I/REQUEST: http://localhost:4242/hvac/on/
I/DATA:
{
  "climate_mode": "Hot",
  "isee_mode": "ISeeOn",
  "powerful_mode": "PowerfulOff",
  "vanne_horizontal_mode": "NotSet",
  "fan_mode": "Auto",
  "vanne_vertical_mode": "Auto",
  "area_mode": "Full",
  "temperature": 21,
  "start_time": -1,
  "end_time": -1
}
I/METHOD: POST
I/RESPONSE:
{
  "command": {
    "area_mode": "Full",
    "climate_mode": "Hot",
    "end_time": -1,
    "fan_mode": "Auto",
    "isee_mode": "ISeeOn",
    "powerful_mode": "PowerfulOff",
    "start_time": -1,
    "temperature": 21,
    "vanne_horizontal_mode": "NotSet",
    "vanne_vertical_mode": "Auto"
  },
  "decoded_command": {
    "area_mode": 128,
    "climate_mode": 8,
    "end_time": null,
    "fan_mode": 128,
    "isee_mode": 64,
    "powerful": 0,
    "start_time": null,
    "temperature": 21,
    "vanne_horizontal_mode": 0,
    "vanne_vertical_mode": 64
  },
  "success": true
}
gouldner commented 6 years ago

@Ericmas001 Great instructions for Raspberry! Thanks. If I run your Flask code as root it works fine. But if I run it as pi I get an error. and nothing is sent. (Code still returns success but I tested and signal isn't sent) 2018-08-16 20:55:53 gpioSetMode: pigpio uninitialised, call gpioInitialise() 2018-08-16 20:55:53 gpioWaveClear: pigpio uninitialised, call gpioInitialise() Error in clearing wave! 127.0.0.1 - - [16/Aug/2018 20:55:53] "GET /hvac/off/ HTTP/1.1" 200 -

my user "pi" is in the group gpio and I am updated to the latest version of stretch. Any idea how to make this work running as pi instead of having a web service running as root?

lumanga commented 5 years ago

@Ericmas001

Dear Sir, I have Raspberry pi 3 with Raspbian LITE OS. I have Broadlink Mini R3 connected to my WiFi. I have IP and MAC of Broadlink inserted into the .py file. I have installed "sudo pip3 install broadlink" and all the files of this project. If I do in terminal: pi@CyberPiLITE:$ python3 SendHVACCmdToRM2.py I receive: 26022601703a0e2a0e2a0e0d0e0d0e0d0e2a0e0d0e0d0e2a0e2a0e0d0e2a0e0d0e0d0e2a0e2a0e0d0e2a0e2a0e0d0e0d0e2a0e0d0e0d0e2a0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e2a0e2a0e0d0e0d0e0d0e2a0e0d0e2a0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e2a0e2a0e0d0e0d0e2a0e2a0e0d0e0d0e0d0e0d0e2a0e2a0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e0d0e2a0e2a0e0d0e2a0e0d0e2a0e0d0e0d0f0032020d

so python works!

Even if I do: pi@CyberPiLITE: $ python3 SendHVACCmdToRM2.py -h I receive: ` usage: SendHVACCmdToRM2.py [-h] [-t HVAC_TEMPERATURE] [-p] [-c HVAC_CLIMATE_CODE] [-Vv HVAC_VANNE_V_CODE] [-F HVAC_FAN_MODE] [--version]

Short sample python HVAC_IR command sender to Broadlink RM2 Mini optional arguments: -h, --help show this help message and exit -t HVAC_TEMPERATURE, --temperature HVAC_TEMPERATURE Set HVAC Temperature in Celcius, Ex: 21 -p, --power HVAC Power, default = Power Off -c HVAC_CLIMATE_CODE, --climate HVAC_CLIMATE_CODE Define Climate Code : C=Cold, H=HOT -Vv HVAC_VANNE_V_CODE, --vanne_vertical HVAC_VANNE_V_CODE Define Vertical Vanne Mode : A=Automatic, S=Swing, B=Bottom, T:Top -F HVAC_FAN_MODE, --fan HVAC_FAN_MODE Define Fan speed : A=Automatic, L=Low, M=Middle, F=Fast, S=Silent ` So I don't understand the command to use after to let my MSD-FD25 work

For example POWER ON, COLD, 23°C, van AUTO, fan AUTO??

jgroezin commented 3 years ago

Thanks for the code and the explanation. Running your python on RPI. Still figuring this out a bit but defintely controls my HVAC.