New DSMR-binding for OpenHAB 2


(Maarten Dekker) #81
package main

import (
    "bufio"
    "fmt"
    "regexp"
    "strings"

    MQTT "[github.com/eclipse/paho.mqtt.golang](http://github.com/eclipse/paho.mqtt.golang)"
    "[github.com/tarm/goserial](http://github.com/tarm/goserial)"
)

var LastReadingTariff1 string
var LastReadingTariff2 string
var LastTariff string
var LastCurrentUsage string
var counter int


var LastReadingGas string

//define a function for the default message handler
var f MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
    fmt.Printf("TOPIC: %s\n", msg.Topic())
    fmt.Printf("MSG: %s\n", msg.Payload())
}

func main() {
    c := &serial.Config{Name: "/dev/ttyUSB1", Baud: 115200}
    s, err := serial.OpenPort(c)

    if err != nil {
        fmt.Println(err)
    }

    //create a ClientOptions struct setting the broker address, clientid, turn
    //off trace output and set the default message handler
    opts := MQTT.NewClientOptions().AddBroker("tcp://<<IPADDRESS>>:1883")
    opts.SetUsername("<<USERNAME>>")
    opts.SetPassword("<<PASSWORD>>")
    opts.SetClientID("dsmr-client")
    opts.SetDefaultPublishHandler(f)

    //create and start a client using the above ClientOptions
    client := MQTT.NewClient(opts)
    if token := client.Connect(); token.Wait() && token.Error() != nil {
        panic(token.Error())
    }

    r := bufio.NewReader(s)
    t, e := Readln(r)
    counter = 0
    for e == nil {

        // Meterstand tarief 1
        if strings.HasPrefix(t, "1-0:1.8.1(") && strings.HasSuffix(t, ")") {
            re := regexp.MustCompile(`(.*1-0:1.8.1\()(.*)(\*kWh\))`)
            match := re.FindStringSubmatch(t)
            if LastReadingTariff1 != match[2] {
                token := client.Publish("dsmr/electric/usagetariff1", 0, false, match[2])
                token.Wait()
                fmt.Print("Meterstand Tarief 1: ", match[2], " kWh\n")
                LastReadingTariff1 = match[2]
            }
        }
        // Meterstand tarief 2
        if strings.HasPrefix(t, "1-0:1.8.2(") && strings.HasSuffix(t, ")") {
            re := regexp.MustCompile(`(.*1-0:1.8.2\()(.*)(\*kWh\))`)
            match := re.FindStringSubmatch(t)
            if LastReadingTariff2 != match[2] {
                token := client.Publish("dsmr/electric/usagetariff2", 0, false, match[2])
                token.Wait()
                fmt.Print("Meterstand Tarief 2: ", match[2], " kWh\n")
                LastReadingTariff2 = match[2]
            }
        }
        // Tarief 1=laag 2=hoog
        if strings.HasPrefix(t, "0-0:96.14.0(") && strings.HasSuffix(t, ")") {
            re := regexp.MustCompile(`(.*0-0:96.14.0\()(.*)(\))`)
            match := re.FindStringSubmatch(t)
            if LastTariff != match[2] {
                token := client.Publish("dsmr/electric/tariff", 0, false, match[2])
                token.Wait()
                fmt.Print("Huidig Tarief: ", match[2], "\n")
                LastTariff = match[2]
            }
        }
        // Huidig stroomverbruik
        if strings.HasPrefix(t, "1-0:1.7.0(") && strings.HasSuffix(t, ")") {
            re := regexp.MustCompile(`(.*1-0:1.7.0\()(.*)(\*kW\))`)
            match := re.FindStringSubmatch(t)
            if LastCurrentUsage != match[2] && counter >= 350 {
                token := client.Publish("dsmr/electric/currentusage", 0, false, match[2])
                token.Wait()
                fmt.Print("Huidig stroomverbruik: ", match[2], " kW\n")
                LastCurrentUsage = match[2]
                counter = 0
            }
        }


        // Gasmeterstand
        if strings.HasPrefix(t, "0-1:24.2.1(") && strings.HasSuffix(t, ")") {
            re := regexp.MustCompile(`(.*0-1:24.2.1\(.*\)\()(.*)(\*m3\))`)
            match := re.FindStringSubmatch(t)
            if LastReadingGas != match[2] {
                token := client.Publish("dsmr/gas/usage", 0, false, match[2])
                token.Wait()
                fmt.Print("Gasmeterstand: ", match[2], " m3\n")
                LastReadingGas = match[2]
            }
        }

        //        fmt.Println(t)
        counter++
        t, e = Readln(r)
    }

    s.Close()
    client.Disconnect(250)

}

// Readln returns a single line (without the ending \n)
// from the input buffered reader.
// An error is returned iff there is an error with the
// buffered reader.
func Readln(r *bufio.Reader) (string, error) {
    var (
        isPrefix bool  = true
        err      error = nil
        line, ln []byte
    )
    for isPrefix && err == nil {
        line, isPrefix, err = r.ReadLine()
        ln = append(ln, line...)
    }
    return string(ln), err
}

(Jaap Schuurman) #82

Hi Maarten,

After installing mosquitto, golang ths little gem worked like a charm :sunglasses:
Could you post you .item list for this pub/sub?
That would help loads with the last problems :stuck_out_tongue_winking_eye:

Grts,
Jaap.


(Maarten Dekker) #83

Sure, will post the item and mqtt openhab config tonight. Will be around 22 CET.

Maarten


(Maarten Dekker) #84

Hi Jaap,

below you will find the items, I also used a rules to calculcate the gas usage per 5 minutes, its not that useful at all, but just post it here as well.

If you want to create some graphs, you could use persistence.

ITEMS

Number CurrentPowerUsage “Power [%.1f]” {mqtt="<[mosquitto:dsmr/currentpowerusage:state:default]"}

Number MeterstandT1 “Meterstand T1 [%.2f]” {mqtt="<[mosquitto:dsmr/electric/usagetariff1:state:default]"}

Number MeterstandT2 “Meterstand T2 [%.2f]” {mqtt="<[mosquitto:dsmr/electric/usagetariff2:state:default]"}

Number Huidigverbruik “Stroomverbruik [%.2f]” {mqtt="<[mosquitto:dsmr/electric/currentusage:state:default]"}

Number Tarief “Huidig Tarief” {mqtt="<[mosquitto:dsmr/electric/tariff:state:default]"}

Number MeterstandGas “Meterstand Gas [%.2f]” {mqtt="<[mosquitto:dsmr/gas/usage:state:default]"}

Number GasVerbruik “Meterstand Gas [%.2f]”

Number LastGasVerbruik “Meterstand Gas [%.2f]”

RULES

rule “Gasverbruik-5minutes”

when

Time cron "0 0/5 * * * ?"

then

if (gasLast5min == 0) {

	gasLast5min = (MeterstandGas.state as DecimalType).doubleValue

	GasVerbruik.postUpdate(0.0)

}

if (gasLast5min != 0) {

	GasVerbruik.postUpdate((MeterstandGas.state as DecimalType).doubleValue - gasLast5min)

	logInfo("energy.rules", "gasLast5min: " + gasLast5min + "MeterstandGas: " + MeterstandGas.state + "Gebruik5min: " + ((MeterstandGas.state as DecimalType).doubleValue - gasLast5min))

	gasLast5min = (MeterstandGas.state as DecimalType).doubleValue

}

end

PERSISTENCE

	Huidigverbruik : strategy = everyChange

	GasVerbruik : strategy = everyMinute

good luck,

Maarten


(rctgamer3) #85

The issue with the M3 meter is because of the following errors (found in the logs):

[DEBUG] [ing.dsmr.internal.DSMRHandlerFactory] - Doesn't support  dsmr:m3_v5_0
[ERROR] [home.core.thing.binding.ThingFactory] - Thing factory (class org.openhab.binding.dsmr.internal.DSMRHandlerFactory) returned null on create thing when it reports to support the thing type (dsmr:m3_v5_0).
[WARN ] [g.discovery.internal.PersistentInbox] - Cannot create thing. No binding found that supports creating a thing of type dsmr:m3_v5_0.

OpenHAB reports the M3 as a “dsmr:m3_v5_0:1_” followed by a long set of numbers.


(Robert) #86

@mvolaart Is there any chance this V2 binding will ever be pulled into the main repo? What is blocking this?


(Kai Kreuzer) #87

Just my words… Would have loved to see it in 2.3!


(Hilbrand Bouwkamp) #88

I started making changes to the binding code as posted in the pull request. Because I wanted it to work for me. My code seems fairly stable (but needs some cleaning up), and I think I should be letting other people know I made these changes. Among other things they fix my review comments in the pr. So that work would not have to be done twice. On the other hand I did make some significant changes in parts of the code that might not necessarily be in line with the intention of the original code. Give these differences and the lack of progress regarding the current pr I’m somewhat reluctant to add my code (when finished) as a pull request to the original pull request. Therefor if @mvolaart can give some insight in his intentions or otherwise what would be a good way to proceed?


(Edwin de Jong) #89

@hilbrand Ah, I just read your comment two days ago. After seeing no progress on the PR for a while, I decided to work on your CR requests and see how far I can get. Unfortunately, it seems our two branches must have diverged. Would it be possible for you to push your branch somewhere so I can CR it?

I would like to add that I regret the current process on this PR. A year ago @mvolaart offered his PR, working the steep learning curve of the Eclipse SmartHome, Openhab 2 and the peculiarities of the CR process itself. Some comments were made a month after and addressed quickly. At one point we should decide to either merge or if anything is still amiss, to make the fixes ourselves.

Because the PR was not merged. It took four (!) months for a major maintainer to review this PR. After these issues had been addressed, you decide to add another round of CRs, seven months after the original PR was posted. Even though these are valid points, it cannot be expected of first-time committers (to the openHAB 2 codebase) to keep fixing every single point. I can look at a piece of Linux kernel source-code and find dozens of possible CR issues in each file. Yet, Linux runs on billions of devices.

I know this is an open source community, and we cannot always find similar short time-windows to do PRs, but 4 and 7 months seems excessive and a good method to create hostility to new contributors.


(Hilbrand Bouwkamp) #90

Don’t blame the messenger :slight_smile:. I don’t think it should be a problem to add code reviews anytime. Ultimately it’s up to the maintainers to merge pull request and if they think the comments are to late to address they can always merge the code. I’ve done numerous reviews last year and never got a comment about it. And from my experience of those code reviews and what others did: yes every single point seems to matter. I also think making the fixes ourselves might not be appreciated by everyone, except for creating pull request on other pull request (what i did by-the-way on the dsmr pr).

I do agree that it’s a problem pr’s remain open for very long. Specifically new bindings remain open for a long time and 1 year seem to be more the norm than the exception. There are several reasons for that, and I don’t know how they can be fixed. I think openHAB prefers quality over speed (everywhere you can read stability is considered one of the strong points of openHAB).

Now to be on topic again. I’m pretty sure our two branches have been diverged given the amount of changes I’ve been making. Are your branches in your github fork? I did look at them, but they are already out of sync to the pr branch (which was push forced last year). Or do you have a branch locally or somewhere else? My kind suggestion would be to not spend to much time on it anymore, but wait for my branch. Although your are free to do whatever you like of course :slight_smile:

I don’t have a branch ready to be code reviewed, as I need a lot cleaning-up to do (but it’s fairly easy to find. Although I would not recommend to fork because I’m going to push force a lot on that branch). But I plan to have it ready in a pr in the coming weeks and then I would appreciate if you’ll do a code review. Hopefully to speed up merging this binding quickly into the main branch. I’ll post an update in this topic.


(Edwin de Jong) #91

Thanks for the kind reply. I’ll wait your changes and if you want to have anything tested or sth like that, just send me a message and I’ll have it running on my local machine for a while. :slight_smile:


(Hilbrand Bouwkamp) #92

Here an update on the DSMR binding. I’ve finalized the work on this binding and created a new pull request #3720. Feel free to do some code reviews to get this binding merged :smile:

In the mean time the binding is available via the Eclipse market place. (If you don’t see it directly in PaperUI, disable/enable market place in configuration to refresh the binding list).

The binding is compatible with openHAB version 2.4.0-SNAPSHOT. If you’ve had a previous version of this binding running, it’s mostly compatible. Only data types with units have been converted to QuantityTypes. And there are some new refresh options. And you can now use the discovery process to discover the meters.

The binding should be fairly stable. If it doesn’t detect during discovery it might show the raw dsmr data in the logging. This can help adding your device. Or else using log levels debug or even trace can help you with more detailed information on what might be wrong. But if it doesn’t work for you please let me know and report your problems here.


(mattnl ) #93

Hi Hilbrand,

Thank you very much for the DSMR2 binding. I have just installed it from the market place. Everything seems to work perfect so far, except for the P1 Timestamp which does not seem to work.

In the DEBUG log the follwowing is visible:

Updating state for channel p1_timestamp_timestamp to value 2018-08-20T19:58:46.000+0200

So the update of the channel seems to work, but my linked item does not get updated. Note the channel name with the duplicate “timestamp”. Maybe that is the problem? Because according to Paper UI, the channel is called dsmr:device_v4:default:p1_timestamp

Even when I update the linked channel of my item to dsmr:device_v4:default:p1_timestamp_timestamp, the item does not get updated.

Any ideas what might be wrong?

Thanks & regards,
Matt


(Wouter Born) #94

Ever since I started testing the binding (July 11th), I haven’t seen any update on the following channels :

  • dsmr:device_v4:default:p1_text_code
  • dsmr:device_v4:default:p1_text_string
  • dsmr:device_v4:default:p1_timestamp

I also reported this in a comment in the PR.


(Hilbrand Bouwkamp) #95

@mstehle It looks like this is a bug. I’ve created a Fix. It’s available in the Eclipse Market place. The correct channel name is dsmr:device_v4:default:p1_timestamp. It was very likely not updated because using the _timestamp_timestamp name isn’t a valid channel (the bug was it used this name) name and I suspect openHAB to then ignore that channel.

@wborn The other 2 channels you mentioned p1_text_code and p1_text_string should work. I don’t see why it shouldn’t work (in contrast to the timestamp). Did you see values with the older version of this binding? You can run with logging trace (this will generate a lot of logging) to see if it’s parsed at all or even has a value.


(mattnl ) #96

Hi Hilbrand,

thank you very much for the quick fix :slight_smile:
I have updated the binding from the market place and can confirm that it is working now.


(Wouter Born) #97

Yes I also see the timestamp with the fix. :slight_smile:

@hilbrand
Probably my meter just doesn’t set any values to it. The P1TelegramParser logs as data:

0-0:96.13.1()
0-0:96.13.0()

There are more example telegrams where this is the case.


(M!) #98

Hi,

Due to an upgrade problem on my device I did a fresh install of OpenHab 2.3.0. However, the DSMR binding available is still only 1.12.0 (‘include legacy 1.x bindings’ is OFF).

I’ve downloaded the newest snapshot (https://github.com/Hilbrand/openhab2-addons/releases). However this version does not work in 2.3 due to: “java.lang.NoSuchMethodError: org.eclipse.smarthome.io.transport.serial.SerialPortIdentifier.isCurrentlyOwned()Z”.

As there is no newer version to install via OpenHab (see: https://dl.bintray.com/openhab/mvn/online-repo/2.3/org/openhab/binding/org.openhab.binding.dsmr), I wonder if there is a place where the 2.3.0 (SNAPSHOT) version can be downloaded?

Shouldn’t it be already available in the repository, since the online manual refers to the new binding (https://www.openhab.org/addons/bindings/dsmr/) and the details clearly state the 1.12.0 is obsolete (https://www.openhab.org/addons/bindings/dsmr1/) ??

Thanks for giving me a pointer.

Michael


(M!) #99

I switched to 2.4.0.M4 which does contains the new binding!


(Edward Voermans) #100

As a newby coming from Domoticz going to OpenHAB(ian) (on Raspberry) I have all my Z-Wave sensors working. Now want to step into connecting DSMR v2.x to cennect my smart meter.
I have walked through the various threads in the community but (pardon my stupidity) caOr Git’t figure out where to download the latest DSMR version.
What I read is that it is somewhere related to Eclipse or Github.
Please share your thoughts.