openhab / openhab1-addons

Add-ons for openHAB 1.x
Eclipse Public License 2.0
3.43k stars 1.71k forks source link

Feature request Smappee binding #3366

Open Roadster opened 8 years ago

Roadster commented 8 years ago

All,

does someone already thought about to integrate a Smappee binding? API: https://smappee.atlassian.net/wiki/display/DEVAPI/SmappeeDevAPI+Home

What is it? .. It will learn your electricity consuming devices and could trigger alerts on events... copied intro-text from their homepage:

Meet the world’s smartest home energy monitor Smappee will turn your house into a smarter, more energy efficient home. It identifies the electrical devices in your house and gives you real-time energy readings as well as costs. You’ll be able to control your home, wherever you are.

would be highly appreciated :-) .. further, i would be happy to support - but i need a hand to find the right steps in an order ;-)

thanks in advance der mischa

MrMontesa commented 8 years ago

+1 I've bought my Smappee a few weeks back and the device is awsome. I've already asked for API access and got my credentials. Will start playing around a bit with scripting. Also saw that there is a 3rd party C# library that should work with the official Smappee API.

watou commented 8 years ago

If I had one of these devices, I would write a binding for it as the communication is very similar to other bindings I've written.

MrMontesa commented 8 years ago

Awesome! You can only connect against the cloud service not the local device. It uses two authentication. I would offer to temporarily share my credentials with you. Then you would have the same API access as if you would own a device. Also happy to heavily beta test and write docu. Thanks again for your offer. Seb

Roadster commented 8 years ago

i am also happy to share my credentials for dev

cheers der mischa

Am 14.12.2015 um 09:08 schrieb Sebastian notifications@github.com:

Awesome! You can only connect against the cloud service not the local device. It uses two authentication. I would offer to temporarily share my credentials with you. Then you would have the same API access as if you would own a device. Also happy to heavily beta test and write docu. Thanks again for your offer. Seb

— Reply to this email directly or view it on GitHub https://github.com/openhab/openhab/issues/3366#issuecomment-164373603.

watou commented 8 years ago

If I had one of these devices...

Just to be clear, I have need of such a device, and I would be motivated to write a solid binding if I actually owned one. I won't consider buying one myself until spring, but that's when I'm less likely to have time to write a binding than now.

MrMontesa commented 8 years ago

Hey watou, fully understand your point. I would donate 50 Euro (which is a quater of the device here in Germany) . Would be great if one of my feature requests could be implemented then. I would like to bind a specific device power consumption to a number item. like:

number washing_machine_power {smappee:item:power}
watou commented 8 years ago

It's a matter of timing. I want exactly the same as you -- bind specific appliances to power consumption numbers, to see where it's all going over time. I hope to be able to move on to this project in the springtime.

janiszie commented 8 years ago

I would also love to donate some euros for making Smappee binding available for OpenHAB.

remogloor commented 8 years ago

Not a binding but with the following script and MQTT you can add smappee support to openhab.

Number  Smappee_P1             "Smappee Phase 1 [%.2f W]"               {mqtt="<[local:device/smappee/Phase1/activePower:state:default]"}
Number  Smappee_P2             "Smappee Phase 2 [%.2f W]"                {mqtt="<[local:device/smappee/Phase2/activePower:state:default]"}
Number  Smappee_P3             "Smappee Phase 3 [%.2f W]"                {mqtt="<[local:device/smappee/Phase3/activePower:state:default]"}

smappee-mqtt.py

#!/usr/bin/env python

import sys, os, requests, datetime, re, logging
import paho.mqtt.publish as publish
import pytz
from ConfigParser import SafeConfigParser
from daemon import runner
from time import sleep
from dateutil.parser import parse

class SmappeeMQTT():
    def __init__(self, logger):
        cfg = SafeConfigParser({"client_id": "smappee-mqtt-"+str(os.getpid()), "hostname": "localhost", "port": "1883", "auth": "False", "retain": "False", "qos": "0"})
        cfg.optionxform = str
        cfg.read("/etc/smappee-mqtt.conf")
        self.smappee = cfg.get("smappee", "hostname")
        self.client_id = cfg.get("mqtt", "client_id")
        self.host = cfg.get("mqtt", "hostname")
        self.port = eval(cfg.get("mqtt", "port"))
        self.topic = cfg.get("mqtt", "topic")
        self.qos = eval(cfg.get("mqtt", "dos"))
        self.retain = eval(cfg.get("mqtt", "retain"))
        if eval(cfg.get("mqtt", "auth")):
            self.auth = { "username": cfg.get("mqtt", "user"), "password": cfg.get("mqtt", "password") }
        else:
            self.auth = None
        self.stdin_path = '/dev/null'
        self.stdout_path = '/dev/null'
        self.stderr_path = '/dev/null'
        self.pidfile_path = '/var/run/smappee-mqtt.pid'
        self.pidfile_timeout = 5
        self.logger = logger

    def run(self):
        reline = re.compile("<BR>")
        refield = re.compile("Load\[(\d+)\] state\[(\d)\] power: (\d\.\d) on (.*)")
        refieldPhase = re.compile(",\s+")
        last = None
        while True:
            while True:
                now = datetime.datetime.utcnow().second
                if last != now:
                    last = now
                    break
                sleep(0.1)
            try:
                requests.post("http://"+self.smappee+"/gateway/apipublic/logon", "admin")
                response = requests.get("http://"+self.smappee+"/gateway/apipublic/reportInstantaneousValues")
                report = response.json()["report"]
                payload = "time="+str(datetime.datetime.utcnow()).replace(" ","T")+"Z"
                isPhase1 = False
                isPhase2 = False
                isPhase3 = False
                phaseTopic = ""
                msgs = []
                for line in re.split(reline, report):
                    isPhase = False
                    if isPhase1:
                        isPhase = True
                        phaseTopic = self.topic + "Phase1/" 
                    if isPhase2:
                        isPhase = True
                        phaseTopic = self.topic + "Phase2/" 
                    if isPhase3:
                        isPhase = True
                        phaseTopic = self.topic + "Phase3/"
                    if isPhase:
                        for field in re.split(refieldPhase, line.strip()):
                            keyValue = field.split("=")
                            key = keyValue[0]
                            value = keyValue[1].split(" ")[0] 
                            msgs.append({ "topic": phaseTopic + key , "payload": value, "qos": self.qos, "retain": self.retain })
                    matchObj = re.match(refield, line)
                    if matchObj:
                        timediff = (datetime.datetime.now(pytz.utc) - parse(matchObj.group(4))).total_seconds()
                        if (timediff < 2):
                            msgs.append({ "topic": self.topic + "Device/" + str(matchObj.group(1)) + "/On", "payload": matchObj.group(2), "qos": self.qos, "retain": self.retain })
                            msgs.append({ "topic": self.topic + "Device/" + str(matchObj.group(1)) + "/Watt", "payload": matchObj.group(3), "qos": self.qos, "retain": self.retain })
                    isPhase1 = line == "Phase 1:"
                    isPhase2 = line == "Phase 2:"
                    isPhase3 = line == "Phase 3:"
                publish.multiple(msgs, hostname=self.host, port=self.port, client_id=self.client_id, auth=self.auth)
            except Exception, e:
                self.logger.warning(e)
                pass

def main(argv=None):
    logger = logging.getLogger("smappee-mqtt")
    logger.setLevel(logging.INFO)
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    handler = logging.FileHandler("/var/log/smappee-mqtt.log")
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    daemon = SmappeeMQTT(logger)
    daemon_runner = runner.DaemonRunner(daemon)
    daemon_runner.daemon_context.files_preserve=[handler.stream]
    daemon.logger = logger
    try:
        daemon_runner.do_action()
    except Exception, e:
        logger.warning(e)
        pass

if __name__ == "__main__":
    main(sys.argv)

Config (/etc/smappee-mqtt.conf):

[smappee]
hostname = smappeeip

[mqtt]
hostname = localhost
port = 1883
topic = device/smappee/
qos = 0
retain = False
auth = True
user = mqttuser
password = mqttpassword
thomassandberg commented 7 years ago

I try to get the mqtt script up running on my ubuntu 16.04 server. But I only get this error message while starting the script:

`$ ./smappee-mqtt.py start

Traceback (most recent call last): File "./smappee-mqtt.py", line 105, in main(sys.argv) File "./smappee-mqtt.py", line 94, in main daemon = SmappeeMQTT(logger) File "./smappee-mqtt.py", line 21, in init self.qos = eval(cfg.get("mqtt", "dos")) File "/usr/lib/python2.7/ConfigParser.py", line 618, in get raise NoOptionError(option, section) ConfigParser.NoOptionError: No option 'dos' in section: 'mqtt'`

What could be wrong, @remogloor ?

9037568 commented 7 years ago

Looks like this line:

self.qos = eval(cfg.get("mqtt", "dos"))

should be this instead:

self.qos = eval(cfg.get("mqtt", "qos"))

thomassandberg commented 7 years ago

Ahh! I didn't catch that typo! Seems like its working now. Thanx @9037568

tj2000bch commented 6 years ago

I tried also to run this mqtt script on debian 9, bat I get always this error: from daemon import runner ImportError: cannot import name runner

Is there a problem with the Python version?

tj2000bch commented 6 years ago

It works cool! Thanx

nikotanghe commented 6 years ago

There is a binding being tested now for openhab2 -> https://community.openhab.org/t/smappee-binding/35670