Broadlink binding for RMx, A1, SPx and MP. Any interest?


(Jordi) #449

Run with rf?


(Hartmut Schwensen) #450

Yes, after fixing the code: https://forum.pimatic.org/topic/3074/python-how-to-integrate-cheap-broadlink-rm3-mini-ir-blaster-with-pimatic


(Oliver) #451

perfect, thanks for sharing - solved my issue too!


(Pierluigi Patuelli) #452

I am very interested on that topic!


(Scott Christian) #453

I managed to figure out how to refernce a device with a .things file
I mean i haven’t tested it yet, but it reports as being online so i’m assuming it’s fine.
Only just did it but here is mine for anyone else that wants it

broadlink:rm2:b40000112233 "Broadlink RM2 Pro" @ "Office" [ ipAddress="10.0.1.218", port=80, iv="THE IV CODE GOES HERE", mac="b4:00:00:11:22:33", authorizationKey="AUTH KEY GOES HERE", pollingInterval=30, mapFilename="broadlink.map" ]

The hex codes can be found here:

https://github.com/mjg59/python-broadlink/blob/master/protocol.md

Just remove the 0x from them


(Neil) #454

brilliant, thanks Scott.

edit: And have just put it in place, and it works a treat. :slight_smile:


(Mohammad Chaaban) #455

thanks… are your devices goes offline and online by itself?


(Scott Christian) #457

Mine have stayed online since I set them up about 6 hours ago.
I’m Stil able to push IR commends as well.


(Joachim Boeddeker) #458

Thanks everybody.

I do not need any help anymore, i amusing the original broadlink-mqtt package, this works like a charm.


(Gonzalo Echevarria) #459

This version PLUS are supported to?

https://www.aliexpress.com/item/2017-New-Broadlink-RM-plus-WiFi-Universal-Smart-Remote-Control-RF-IR-433-315-Hmz-for/32808024597.html

regards


(Neil) #460

I’ve got two RM3s running with Cato’s Broadlink binding, and they both auto-detect and don’t go offline in PaperUI and work great.

I did have 2 RM2’s using it, and they wouldn’t auto-detect (so had to be setup manually). While they were sometimes showing offline in PaperUI, they still worked via openHAB.


(Joachim Boeddeker) #461

Thanks @DSTM, but i do not use this binding anymore because of @Cato_Sognen is unreachable and some time in the future this binding will not work anymore.

I switched to the this broadlink-mqtt package, it works like a charm. Usability is also much better because it is possible to record remotes via mqtt. No more copying of files and such stuff.


(Neil) #462

I don’t see why the binding will stop working, but if it does then there might be another option available by then (if not, there’s alternatives such as what you’re using).

And you say what you’re using works like a charm, but i replied when you’d posted having issues.

But whatever works for you. :slight_smile:


(Joachim Boeddeker) #463

Some time in the future some interfaces will change and without access to the source code this is a dead end.

At first i was using a fork, this didn’t go well. As soon as i switched to the original everything worked. I also enjoy the ability to record commands without additional effort.


(Nakh Home) #464

Hi

try this code

#!/usr/bin/env python

import paho.mqtt.client as paho  # pip install paho-mqtt
import broadlink  # pip install broadlink
import os
import sys
import time
import logging
import logging.config
import socket
import sched
HAVE_TLS = True
try:
    import ssl
except ImportError:
    HAVE_TLS = False
from threading import Thread
from test import TestDevice

# read initial config files
dirname = os.path.dirname(os.path.abspath(__file__)) + '/'
logging.config.fileConfig(dirname + 'logging.conf')
CONFIG = os.getenv('BROADLINKMQTTCONFIG', dirname + 'mqtt.conf')


class Config(object):
    def __init__(self, filename=CONFIG):
        self.config = {}
        self.config['ca_certs']     = None
        self.config['tls_version']  = None
        self.config['certfile']     = None
        self.config['keyfile']      = None
        self.config['tls_insecure'] = False
        self.config['tls']          = False
        execfile(filename, self.config)

        if HAVE_TLS == False:
            logging.error("TLS parameters set but no TLS available (SSL)")
            sys.exit(2)

        if self.config.get('ca_certs') is not None:
            self.config['tls'] = True

        if self.config.get('tls_version') is not None:
            if self.config.get('tls_version') == 'tlsv1':
                self.config['tls_version'] = ssl.PROTOCOL_TLSv1
            if self.config.get('tls_version') == 'tlsv1.2':
                # TLS v1.2 is available starting from python 2.7.9 and requires openssl version 1.0.1+.
                if sys.version_info >= (2,7,9):
                    self.config['tls_version'] = ssl.PROTOCOL_TLSv1_2
                else:
                    logging.error("TLS version 1.2 not available but 'tlsv1.2' is set.")
            	    sys.exit(2)
            if self.config.get('tls_version') == 'sslv3':
                self.config['tls_version'] = ssl.PROTOCOL_SSLv3

    def get(self, key, default='special empty value'):
        v = self.config.get(key, default)
        if v == 'special empty value':
            logging.error("Configuration parameter '%s' should be specified" % key)
            sys.exit(2)
        return v


try:
    cf = Config()
except Exception, e:
    print "Cannot load configuration from file %s: %s" % (CONFIG, str(e))
    sys.exit(2)

qos = cf.get('mqtt_qos', 0)
retain = cf.get('mqtt_retain', False)

topic_prefix = cf.get('mqtt_topic_prefix', 'broadlink/')


# noinspection PyUnusedLocal
def on_message(client, device, msg):
    command = msg.topic[len(topic_prefix):]

    if command == 'temperature' or command == 'energy':  # internal notification
        return

    try:
        action = str(msg.payload)
        logging.debug("Received MQTT message " + msg.topic + " " + action)

        if command == 'power':
            if device.type == 'SP1' or device.type == 'SP2':
                state = action == 'on'
                logging.debug("Setting power state to {0}".format(state))
                device.set_power(1 if state else 0)
                return

            if device.type == 'MP1':
                parts = action.split("/", 2)
                if len(parts) == 2:
                    sid = int(parts[0])
                    state = parts[1] == 'on'
                    logging.debug("Setting power state of socket {0} to {1}".format(sid, state))
                    device.set_power(sid, state)
                    return

        if device.type == 'RM2':
            file = dirname + "commands/" + command

            if action == '' or action == 'auto':
                record_or_replay(device, file)
                return
            elif action == 'record':
                record(device, file)
                return
            elif action == 'replay':
                replay(device, file)
                return
            elif action == 'macro':
                file = dirname + "macros/" + command
                macro(device, file)
                return

        logging.debug("Unrecognized MQTT message " + action)
    except Exception:
        logging.exception("Error")


# noinspection PyUnusedLocal
def on_connect(client, device, flags, result_code):
    topic = topic_prefix + '#'
    logging.debug("Connected to MQTT broker, subscribing to topic " + topic)
    mqttc.subscribe(topic, qos)


# noinspection PyUnusedLocal
def on_disconnect(client, device, rc):
    logging.debug("OOOOPS! Broadlink disconnects")
    time.sleep(10)


def record_or_replay(device, file):
    if os.path.isfile(file):
        replay(device, file)
    else:
        record(device, file)


def record(device, file):
    logging.debug("Recording command to file " + file)
    # receive packet
    device.enter_learning()
    ir_packet = None
    attempt = 0
    while ir_packet is None and attempt < 6:
        time.sleep(5)
        ir_packet = device.check_data()
        attempt = attempt + 1
    if ir_packet is not None:
        # write to file
        directory = os.path.dirname(file)
        if not os.path.exists(directory):
            os.makedirs(directory)
        with open(file, 'wb') as f:
            f.write(str(ir_packet).encode('hex'))
        logging.debug("Done")
    else:
        logging.warn("No command received")


def replay(device, file):
    logging.debug("Replaying command from file " + file)
    with open(file, 'rb') as f:
        ir_packet = f.read()
    device.send_data(ir_packet.decode('hex'))


def macro(device, file):
    logging.debug("Replaying macro from file " + file)
    with open(file, 'rb') as f:
        for line in f:
            line = line.strip(' \n\r\t')
            if len(line) == 0 or line.startswith("#"):
                continue
            if line.startswith("pause "):
                pause = int(line[6:].strip())
                logging.debug("Pause for " + str(pause) + " milliseconds")
                time.sleep(pause / 1000.0)
            else:
                command_file = dirname + "commands/" + line
                replay(device, command_file)


def get_device(cf):
    device_type = cf.get('device_type', 'lookup')
    if device_type == 'lookup':
        local_address = cf.get('local_address', None)
        lookup_timeout = cf.get('lookup_timeout', 20)
        devices = broadlink.discover(timeout=lookup_timeout) if local_address is None else \
            broadlink.discover(timeout=lookup_timeout, local_ip_address=local_address)
        if len(devices) == 0:
            logging.error('No Broadlink device found')
            sys.exit(2)
        if len(devices) > 1:
            logging.error('More than one Broadlink device found (' + ', '.join([d.host for d in devices]) + ')')
            sys.exit(2)
        return devices[0]
    elif device_type == 'test':
        return TestDevice(cf)
    else:
        host = (cf.get('device_host'), 80)
        mac = bytearray.fromhex(cf.get('device_mac').replace(':', ' '))
        if device_type == 'rm':
            return broadlink.rm(host=host, mac=mac)
        elif device_type == 'sp1':
            return broadlink.sp1(host=host, mac=mac)
        elif device_type == 'sp2':
            return broadlink.sp2(host=host, mac=mac)
        elif device_type == 'a1':
            return broadlink.a1(host=host, mac=mac)
        elif device_type == 'mp1':
            return broadlink.mp1(host=host, mac=mac)
        else:
            logging.error('Incorrect device configured: ' + device_type)
            sys.exit(2)


def broadlink_rm_temperature_timer(scheduler, delay, device):
    scheduler.enter(delay, 1, broadlink_rm_temperature_timer, [scheduler, delay, device])

    try:
        temperature = str(device.check_temperature())
        topic = topic_prefix + "temperature"
        logging.debug("Sending RM temperature " + temperature + " to topic " + topic)
        mqttc.publish(topic, temperature, qos=qos, retain=retain)
    except:
        logging.exception("Error")


def broadlink_sp_energy_timer(scheduler, delay, device):
    scheduler.enter(delay, 1, broadlink_sp_energy_timer, [scheduler, delay, device])

    try:
        energy = str(device.get_energy())
        topic = topic_prefix + "energy"
        logging.debug("Sending SP energy " + energy + " to topic " + topic)
        mqttc.publish(topic, energy, qos=qos, retain=retain)
    except:
        logging.exception("Error")


class SchedulerThread(Thread):
    def __init__(self, scheduler):
        Thread.__init__(self)
        self.scheduler = scheduler

    def run(self):
        try:
            self.scheduler.run()
        except:
            logging.exception("Error")


if __name__ == '__main__':
    device = get_device(cf)
    device.auth()
    logging.debug('Connected to %s Broadlink device at %s' % (device.type, device.host))

    clientid = cf.get('mqtt_clientid', 'broadlink-%s' % os.getpid())
    # initialise MQTT broker connection
    mqttc = paho.Client(clientid, clean_session=cf.get('mqtt_clean_session', False), userdata=device)

    mqttc.on_message = on_message
    mqttc.on_connect = on_connect
    mqttc.on_disconnect = on_disconnect

    mqttc.will_set('clients/broadlink', payload="Adios!", qos=0, retain=False)

    # Delays will be: 3, 6, 12, 24, 30, 30, ...
    # mqttc.reconnect_delay_set(delay=3, delay_max=30, exponential_backoff=True)

    if cf.get('tls') == True:
        mqttc.tls_set(cf.get('ca_certs'), cf.get('certfile'), cf.get('keyfile'), tls_version=cf.get('tls_version'), ciphers=None)

    if cf.get('tls_insecure'):
        mqttc.tls_insecure_set(True)

    mqttc.username_pw_set(cf.get('mqtt_username'), cf.get('mqtt_password'))
    mqttc.connect(cf.get('mqtt_broker', 'localhost'), int(cf.get('mqtt_port', '1883')), 60)

    broadlink_rm_temperature_interval = cf.get('broadlink_rm_temperature_interval', 0)
    if device.type == 'RM2' and broadlink_rm_temperature_interval > 0:
        scheduler = sched.scheduler(time.time, time.sleep)
        scheduler.enter(broadlink_rm_temperature_interval, 1, broadlink_rm_temperature_timer,
                        [scheduler, broadlink_rm_temperature_interval, device])
        # scheduler.run()
        tt = SchedulerThread(scheduler)
        tt.daemon = True
        tt.start()

    broadlink_sp_energy_interval = cf.get('broadlink_sp_energy_interval', 0)
    if device.type == 'SP2' and broadlink_sp_energy_interval > 0:
        scheduler = sched.scheduler(time.time, time.sleep)
        scheduler.enter(broadlink_sp_energy_interval, 1, broadlink_sp_energy_timer,
                        [scheduler, broadlink_sp_energy_interval, device])
        # scheduler.run()
        tt = SchedulerThread(scheduler)
        tt.daemon = True
        tt.start()

    while True:
        try:
            mqttc.loop_forever()
        except socket.error:
            time.sleep(5)
        except KeyboardInterrupt:
            sys.exit(0)
        except:
            logging.exception("Error")


The config file :slight_smile:

# Type of device. Valid options are 'lookup', 'rm', 'sp1', 'sp2', 'a1', 'mp1'
device_type = 'rm' # use lookup

## lookup parameters
lookup_timeout = 20
#local_address = '127.0.0.1'

## parameters for direct connection
device_host = '192.168.1.107'
device_mac  = '34:EA:34:51:xx.xx'

## MQTT connection parameters
mqtt_broker = 'localhost'       # default: 'localhost'
mqtt_port = 1883                # default: 1883
mqtt_clientid = 'mqtt_mini_2'
mqtt_username = ''
mqtt_password = ''
mqtt_topic_prefix = 'broadlink/mqtt_mini_2/'


#/etc/openhab2/scripts/MQTT/broadlink/mqtt_mini_2/mqtt.conf

## MQTT TLS parameters
# Required with TLS: a string path to the Certificate Authority certificate files that are to be treated as trusted by this client.
# ca_certs = '/path/to/ca_certsfile'
# Optional Clients Cert/Key
# certfile = '/path/to/certfile'
# keyfile  = '/path/to/keyfile'
# Required TLS version. Valid values: 'sslv3', 'tlsv1', 'tlsv1.2'
# tls_version = 'tlsv1.2'

## extra parameters
#broadlink_rm_temperature_interval = 120 # publish temperature from RM device to broadlink/temperature topic every two minutes
#broadlink_sp_energy_interval = 30 # publish energy from SP device to broadlink/energy topic every 30 seconds

create a service under /usr/lib/systemd/system

with this content :slight_smile:

[Unit]
Description=Starts and stops the Broadink Python script
Documentation=https://github.com/psyciknz/broadlink-mqtt
Wants=network-online.target
After=network-online.target

[Service]
EnvironmentFile=/etc/openhab2/scripts/MQTT/broadlink/mqtt_mini_2/mqtt.conf
User=openhab
Group=openhab
WorkingDirectory=/etc/openhab2/scripts/MQTT/broadlink/mqtt_mini_2/
PermissionsStartOnly=true
ExecStart=/usr/bin/python /etc/openhab2/scripts/MQTT/broadlink/mqtt_mini_2/mqtt_mini_2.py
# Shutdown delay in seconds, before process is tried to be killed with KILL (if configured)
TimeoutStopSec=20
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

example of an item:
String Clim_3 “AC”

rule "ac noya"
when
    Item Clim_3 received command
then 

        switch (receivedCommand) 
        {
		case "on" :
                        publish("mosquitto", "broadlink/mqtt_mini_2/ac/on", "replay") 
		case "off" :
                        publish("mosquitto", "broadlink/mqtt_mini_2/ac/off", "replay") 

		case "heat" :
                        publish("mosquitto", "broadlink/mqtt_mini_2/ac/heat", "replay") 
                case "cold" :
                        publish("mosquitto", "broadlink/mqtt_mini_2/ac/cold", "replay") 
                case "plus" :
                        publish("mosquitto", "broadlink/mqtt_mini_2/ac/plus", "replay") 
                case "minus" :
                        publish("mosquitto", "broadlink/mqtt_mini_2/ac/minus", "replay")
         }
end

Broadlink-mqtt integration with openhab
(Gustavo Z. B.) #465

Hi guys, My RM2 inform the temperature 0. Anybody have this problem?
iR is working correctly e the temperature is above 20ºC.
In my network have one RM2 and one rm3 mini.

image


(Gustavo Z. B.) #466

Were you able to control the somfy shutter with the broadlink RM pro?


(Neil) #467

I’ve got 2 RM2’s, that the app tells me are slightly different (one is a ‘Pro’, and one is ‘Pro Plus’, or something). One has temperature, and the other doesn’t.

The one with temperature isn’t really usable anyway, because every now and then it gives a random very high or random very low reading. I gave up on it for temperature and got another device.


How to install 3rd Party Addons - Broadlink RM Pro
(Carlos Roa) #468

BlackBeanControl is great for RM mini. It works like a charm. But does not seem to be suitable for SPx sockets. Does anybody know how to control them without the binding?


(Dave) #469

+1 for this. Have a harmony hube, but looking to buy a couple RM Pros due to the cost mainly and the added benefit of RF