Mios binding EOL

With 3.x removing compatibility layer, seems like the mios binding is about to be left behind. I don’t posses the skillset(or time to learn how) to port it. Thoughts on alternatives? I enjoy using my vera edge as my zwave controller as I run OH as a vm on a cluster. @guessed hasn’t been seen since 7/2019.

A V2 binding was started in 2017, but due to the amount of time it took to get the code reviewed the original author seems to have lost interest.

Then, a year ago, someone else showed interest in picking it back up, but nothing seems to have come of it.

I use Z-Wave through a Vera Lite and the MiOS v1 binding, which means I can’t properly move to OH3 either.

I also use mios to control my alarm panel.
The only reason not to install OpenHAB 3 :unamused:

In the near term you could run it on OH2 and use the remote OpenHAB binding on OH3.

Similar situation here. I run the mainline zwave binding, but I have a remote vera using mios binding about 400 ft away for the garage where reception is poor.

The remote openhab suggestion might work. Either that or i’ll have to try a serial over IP option.

It is currently http only, so unencrypted.

Yeah, the remote OH thing is neat but a non-starter as I don’t want legacy OH or I would just stay on 2.x for my main install. I’m not looking for new features specifically, just don’t want to fall behind.

I eyeballed the homeseer z-net thing a while back which is just a raspberry pi with zwave dongle. But, seems like I could do something better myself. I’ve just been down the rpi oh days and didn’t enjoy the experience.

I guess I was hoping to rattle the right person into porting the binding :slight_smile:

I think OH recommends non-developers use bountysource for that. AKA “put your money where your mouth is”. :wink:

If you have only a few devices to control, you may find that the http action and/or binding with some rules could work for you. I briefly did this, but my Vera is now gone, so no more need. You can also set up the Vera to send sensor results through the REST api to OH. But this is probably impractical if you have a lot of devices or sensors.

I suppose. I would assume the amount of money a developer would want to write a binding would be far out of what I could justify which is why I use opensource software in the first place.

I have far too many devices to use shims between the two unfortunately.

I really don’t want to try to learn java! :laughing: I’m good with posh and get by with c++ for microcontrollers. Took python a while back but forgot more than I learned by now.

1 Like

I don’t have many devices, so this is of interest. I’ll do some searching myself, but if you have any useful links drop them here!

I haven’t used this in a long time, and I no longer have a Vera to test, but here’s one sample of controlling the Vera from OH. Set up an Item for what you want to control, then send the http get request to Vera appropriately.

Change the IP appropriately, and change the DeviceNum appropriately.

On the Vera side you can post updates to OH on the REST api. I think I may have some examples of that too, but it may take a little longer to dig up.

val VERA_SWITCH = "http://192.168.86.205:3480/data_request?id=action&output_format=xml&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget"

rule "Kitchen Light"
when
        Item Kitchen_Light received command
then
        // logInfo("Kitchen Light", "Kitchen Light command received: " + receivedCommand)
        if (receivedCommand == ON) {
                sendHttpGetRequest(VERA_SWITCH + "&DeviceNum=31&newTargetValue=1")
        } else if (receivedCommand == OFF) {
                sendHttpGetRequest(VERA_SWITCH + "&DeviceNum=31&newTargetValue=0")
        } else {
                logInfo("Kitchen Light", "Command not handled")
        }
end

I’d definitely be interested, thanks! No rush though.


For others following along, I’ve (eventually) found out that you can find the details and methods for all your attached devices by going to (swap the IP address for your Vera IP address):

http://192.168.1.91:3480/data_request?id=invoke

For me, this shows the following:

image

Clicking on device 4, the radiator, shows the following:

Now, I’m mostly interested in setting the temperature, so I click SetCurrentSetpoint (NewCurrentSetpoint), which shows the following:

image

Not too encouraging. However, when clicking on SetCurrentSetpoint (NewCurrentSetpoint) on the previous page, the URL which is used is:

http://192.168.1.91:3480/data_request?id=action&DeviceNum=4&serviceId=urn:upnp-org:serviceId:TemperatureSetpoint1_Heat&action=SetCurrentSetpoint&NewCurrentSetpoint=

You can see there is no value after NewCurrentSetpoint=. Adding a value in, such as 19, and trying again, now shows a valid XML response, and eventually the thermostat itself updates.

image

EDIT:
Just dumping some info so I don’t lose it:

To perform a valid action, you need id=action and action= in the URL.
To get a variable, you need id=variableget and Variable= (case sensitive!) in the URL.

Yeah, this is the api that I think the current binding talks to. I just don’t even come close to having the java skills to write something that talks to it.

To go from Vera to OH, I used a Lua function like the one below. At the time I left Vera, this was with AltUI, but presumably it works with the standard Vera. Create a scene and use the function below (or the guts of the function) in the Lua code for the scene to set the OH item as desired. Set up whatever triggers you would like for the scene to activate this.

Another method is simply to poll the Vera periodically to get values. I generally prefer push as shown below, but the poll could be fine for some uses.

I cannot test this as I no longer have a Vera, but it should be reasonably close to what is needed.

function setOpenHabItem(item, value)
  local http = require("socket.http")
  local ltn12 = require("ltn12")
  local path = "http://192.168.86.212:8080/rest/items/" .. item
  local payload = "0" -- default is to turn off
  payload = value

  luup.log("setOpenHabItem payload is " .. payload)

  local response_body = { }
    local res, code, response_headers, status = http.request
    {
      url = path,
      method = "POST",
      headers =
      {
        ["Content-Type"] = "text/plain",
        ["Content-Length"] = payload:len()
      },
      source = ltn12.source.string(payload),
      sink = ltn12.sink.table(response_body)
    }
    if res ~= 0 or status ~= 200 then
       luup.log("res is: " .. res .. " and status is: " .. status)
    end
end

2 Likes

Thanks for this @jswim788!

In the end I opted for the polling method, as this means I only need to maintain one system’s code (openHAB).

If this is useful for anyone else I wrote the below python classes to interact with my thermostat and boiler relay, and now use these classes in my Jython rules. Note: this is the first time I have ever written classes in any language, so use with an abundance of caution! Note that I am using the openHAB LogAction, so I guess it’s not quite a standalone python class…

import requests
from core.actions import LogAction

vera_ip = "192.168.1.91"
vera_port = "3480"

class Vera:
    def __init__(self):
        self.ipaddress = vera_ip
        self.port = vera_port
        self.DeviceNum = 1
        self.ZWaveNetworkServiceId = "urn:micasaverde-com:serviceId:ZWaveNetwork1"

    def build_url(self, id, DeviceNum, serviceId, action):
        url = "http://{}:{}".format(self.ipaddress, self.port)
        url = url + "/data_request?"
        url = url + "id={}".format(id)
        url = url + "&DeviceNum={}".format(DeviceNum)
        url = url + "&serviceId={}".format(serviceId)
        url = url + "&{}".format(action)
        url = url + "&output_format=text"

        return str(url)

    def set_parameter(self, DeviceNum, serviceId, action_name, parameter_name, parameter_value):

        action = "action={}&{}={}".format(action_name, parameter_name, parameter_value)

        url = self.build_url("action", DeviceNum, serviceId, action)

        r = self.send_request(url)

        if r == "OK":
            return True
        else:
            return str(r)

    def get_parameter(self, DeviceNum, serviceId, parameter_name):

        action = "Variable={}".format(parameter_name)

        url = self.build_url("variableget", DeviceNum, serviceId, action)

        r = self.send_request(url)

        return str(r)

    def send_request(self, url):
        
        r = requests.get(url)

        return r.content

    def get_zwave_network_status(self):
        
        r = self.get_parameter(self.DeviceNum, self.ZWaveNetworkServiceId,"NetStatusText")

        return str(r.upper())

    def get_zwave_version(self):
        
        r = self.get_parameter(self.DeviceNum, self.ZWaveNetworkServiceId,"VersionInfo")

        return str(r.upper())
    
    def get_zwave_last_update(self):
        
        r = self.get_parameter(self.DeviceNum, self.ZWaveNetworkServiceId,"LastUpdate")

        return str(r.upper())


    class relay:
        def __init__(self):
            self.DeviceNum = 6
            self.SwitchServiceId = "urn:upnp-org:serviceId:SwitchPower1"
            self.HaDeviceServiceId = "urn:micasaverde-com:serviceId:HaDevice1"
            self.HVACModeServiceId = "urn:upnp-org:serviceId:HVAC_UserOperatingMode1"
            self.HVACStateServiceId = "urn:micasaverde-com:serviceId:HVAC_OperatingState1"

        def set_switch_status(self, newTargetValue):
            r = Vera().set_parameter(self.DeviceNum, self.SwitchServiceId, "SetTarget", "newTargetValue", newTargetValue)

            if r == True:
                LogAction.logInfo("set_switch_status", "Switched to {}".format(newTargetValue))
            else:
                LogAction.logWarn("set_switch_status","Switch change failed. {}".format(r))

        def get_switch_status(self):
            r = Vera().get_parameter(self.DeviceNum, self.SwitchServiceId,"Status")

            #LogAction.logInfo("get_switch_status", "Switch status: {}".format(r))

            return str(r)
        
        def get_comms_status(self):

            r = Vera().get_parameter(self.DeviceNum, self.HaDeviceServiceId, "CommFailure")

            return int(r)

        def get_mode_status(self):

            r = Vera().get_parameter(self.DeviceNum, self.HVACModeServiceId,"ModeStatus")

            return str(r.upper())

        def get_mode_state(self):

            r = Vera().get_parameter(self.DeviceNum, self.HVACStateServiceId,"ModeState")

            return str(r.upper())

        def get_last_update(self):

            r = Vera().get_parameter(self.DeviceNum, self.HaDeviceServiceId,"LastUpdate")

            return str(r)

    class thermostat:
        def __init__(self):
            self.DeviceNum = 4
            self.SetpointServiceId = "urn:upnp-org:serviceId:TemperatureSetpoint1_Heat"
            self.SensorServiceId = "urn:upnp-org:serviceId:TemperatureSensor1"
            self.HaDeviceServiceId = "urn:micasaverde-com:serviceId:HaDevice1"
            self.HVACModeServiceId = "urn:upnp-org:serviceId:HVAC_UserOperatingMode1"

        def set_setpoint(self, setpointTemp):

            r = Vera().set_parameter(self.DeviceNum, self.SetpointServiceId, "SetCurrentSetpoint", "NewCurrentSetpoint", setpointTemp)

            if r == True:
                LogAction.logInfo("set_setpoint", "Thermostat changed to {}".format(setpointTemp))
            else:
                LogAction.logWarn("set_setpoint","Thermostat change failed. {}".format(r))
        
        def get_current_setpoint(self):

            r = Vera().get_parameter(self.DeviceNum, self.SetpointServiceId,"CurrentSetpoint")

            #LogAction.logInfo("get_current_setpoint", "Current setpoint: {}".format(r))

            return str(r)

        def get_target_setpoint(self):

            r = Vera().get_parameter(self.DeviceNum, self.SetpointServiceId,"SetpointTarget")

            #LogAction.logInfo("get_target_setpoint", "Target setpoint: {}".format(r))

            return str(r)

        def get_current_temperature(self):

            r = Vera().get_parameter(self.DeviceNum, self.SensorServiceId,"CurrentTemperature")

            #LogAction.logInfo("get_current_temperature", "Current temperature: {}".format(r))

            return str(r)

        def get_battery_level(self):

            r = Vera().get_parameter(self.DeviceNum, self.HaDeviceServiceId,"BatteryLevel")

            #LogAction.logInfo("get_battery_level", "Battery level: {}".format(r))

            return str(r)

        def get_battery_level_last_update(self):

            r = Vera().get_parameter(self.DeviceNum, self.HaDeviceServiceId,"BatteryDate")

            return str(r)


        def get_last_update(self):

            r = Vera().get_parameter(self.DeviceNum, self.HaDeviceServiceId,"LastUpdate")

            return str(r)

        def get_mode_status(self):

            r = Vera().get_parameter(self.DeviceNum, self.HVACModeServiceId,"ModeStatus")

            return str(r.upper())

        def get_comms_status(self):

            r = Vera().get_parameter(self.DeviceNum, self.HaDeviceServiceId, "CommFailure")

            return int(r)

To use these classes within a rule I:

  • Saved the above into $OPENHAB_CONF/automation/lib/python/personal/heating_functions.py
  • Add the following to the top of any rules file which will use the classes:
import personal.heating_functions
reload(personal.heating_functions)
from personal.heating_functions import Vera
  • To set the thermostat setpoint in a rule, for example:
Vera().thermostat().set_setpoint(20)
  • To get the Z-Wave network status:
Vera().get_zwave_network_status()

EDIT 23/11/2020: Added more class methods.

I went for the following approach. I used MQTT too communicate between OH and VERA.

For the publishing of the device changes I use Vera2MQTT plugin on my VERA. This will generate Vera/Events for all device changes.
For changes invoked from OH side I created a Vera/Command topic which will be converted to https requests.

Here are the steps I took:

I already had a MQTT server running.

I installed Vera2MQTT plugin on my VERA. See https://community.getvera.com/t/mqtt-client-plugin/190658/77 for the details
Extended my MQTT bridge with all my zwave devices. See https://community.openhab.org/t/mios-binding-eol/107711/13 how to lookup the device numbers
An example:

mqtt.things file:

Thing topic vera-device-garden-light “Garden light” @ “VERA”
{
Channels:
Type switch : power “Power” [ stateTopic=“Vera/Events/12”, transformationPattern=“REGEX:(.“Status”.)∩JSONPATH:$.Status”, commandTopic=“Vera/Command/12/relay”, on=“1”, off=“0” ]
}

I also added a publish trigger to the MQTT broker to subscribe to all Vera/Command/# topics

Channels:
        Type publishTrigger : vera-mqtt "Trigger on vera commands" [ stateTopic="Vera/Command/#", separator="#" ]

vera.items file:

Switch Outside_Garden_Light “Garden light” { channel=“mqtt:topic:mosquitto:vera-device-garden-light:power” }

Create a rule to translate mqtt command to https request

vera.rules file:

rule "Translate VERA mqtt commands to http requests"
when 
      Channel "mqtt:broker:mosquitto:vera-mqtt" triggered
then
   var parts = receivedEvent.getEvent.toString.split("#")
   var topics = parts.get(0).toString.split("/")
   var payload = parts.get(1)
   var deviceNumber = topics.get(2)
   var commandType = topics.get(3)

   logInfo("vera", "Command received for dev: " + deviceNumber.toString() + ", type: " + commandType.toString() + ", payload: " + payload.toString())

   switch(commandType)
   {
      case "relay":
      {
            var url = "http://**<vera ip>**:3480/data_request?id=action&DeviceNum=" + deviceNumber + "&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=" + payload
            logInfo("mqtt", "TEST: " + url.toString())
            sendHttpGetRequest(url.toString())
      }
      case "dimmer":
      {
            var url = "http://**<vera ip>**:3480/data_request?id=action&DeviceNum=" + deviceNumber + "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=" + payload
            logInfo("mqtt", "TEST: " + url.toString())
            sendHttpGetRequest(url.toString())
      }
   }
end

And at last removed the MIOS binding which prevented me to upgrade to OH3.

1 Like

The MQTT works well to publish updates. I’m trying to create a better way of sending data back to the Vera that doesn’t require a 1:1 configuration of deviceID and MQTT topic. The best idea I can come up with is caching a local copy of a mapping table between item/Vera name and its device ID that can be referenced via a rule, there is also a way of reading metadata (could be Vera deviceID) from items using jython. Has another else thought of a creative method of controlling multiple devices without having to code specific items?

More nonsense from me again!

I’m slowly testing OH3, and I think I’m going to control and monitor my Vera using the HTTP Binding, rather than the complicated setup I had previously.

I’m sticking with configuration files, so below are the Things and Items configurations that form a working concept for my small heating setup.

Things

//VERA
Thing http:url:vera "Vera" [
	baseURL = "http://192.168.1.91:3480/data_request?DeviceNum=1&serviceId=urn:micasaverde-com:serviceId:ZWaveNetwork1&output_format=text",
	refresh = "300",
	ignoreSSLErrors = "true"
]
{
	Channels:
		Type string: NetStatusText "Network Status" [
			mode = "READONLY",
			stateExtension = "&id=variableget&Variable=NetStatusText"
		]
		Type string: VersionInfo "Version Info" [
			mode = "READONLY",
			stateExtension = "&id=variableget&Variable=VersionInfo"
		]
		Type datetime: LastUpdate "Last Update" [
			mode = "READONLY",
			stateExtension = "&id=variableget&Variable=LastUpdate"
		]
}

//THERMOSTAT
Thing http:url:thermostat "Thermostat" [
	baseURL = "http://192.168.1.91:3480/data_request?DeviceNum=4&output_format=text",
	refresh = "60",
	ignoreSSLErrors = "true"
]
{
	Channels:
		Type number: CurrentSetpoint "Current Setpoint" [
			mode = "READONLY",
			stateExtension = "&serviceId=urn:upnp-org:serviceId:TemperatureSetpoint1_Heat&id=variableget&Variable=CurrentSetpoint"
		]
		Type number: SetpointTarget "Setpoint Target" [
			mode = "READWRITE",
			stateExtension = "&serviceId=urn:upnp-org:serviceId:TemperatureSetpoint1_Heat&id=variableget&Variable=SetpointTarget",
			commandExtension = "&serviceId=urn:upnp-org:serviceId:TemperatureSetpoint1_Heat&id=action&action=SetCurrentSetpoint&NewCurrentSetpoint=%2$s"
		]
		Type number: CurrentTemperature "Current Temperature" [
			mode = "READONLY",
			stateExtension = "&serviceId=urn:upnp-org:serviceId:TemperatureSensor1&id=variableget&Variable=CurrentTemperature"
		]
		Type number: BatteryLevel "Battery Level" [
			mode = "READONLY",
			stateExtension = "&serviceId=urn:micasaverde-com:serviceId:HaDevice1&id=variableget&Variable=BatteryLevel"
		]
		Type datetime: BatteryDate "Battery Date" [
			mode = "READONLY",
			stateExtension = "&serviceId=urn:micasaverde-com:serviceId:HaDevice1&id=variableget&Variable=BatteryDate"
		]
		Type datetime: LastUpdate "Last Update" [
			mode = "READONLY",
			stateExtension = "&serviceId=urn:micasaverde-com:serviceId:HaDevice1&id=variableget&Variable=LastUpdate"
		]
		Type string: ModeStatus "Mode Status" [
			mode = "READONLY",
			stateExtension = "&serviceId=urn:upnp-org:serviceId:HVAC_UserOperatingMode1&id=variableget&Variable=ModeStatus"
		]
		Type string: CommFailure "Comm Failure" [
			mode = "READONLY",
			stateExtension = "&serviceId=urn:micasaverde-com:serviceId:HaDevice1&id=variableget&Variable=CommFailure",
			stateTransformation = "MAP:vera2online.map"
		]
}

//RELAY
Thing http:url:relay "Relay" [
	baseURL = "http://192.168.1.91:3480/data_request?DeviceNum=6&output_format=text",
	refresh = "120",
	ignoreSSLErrors = "true"
]
{
	Channels:
		Type switch: Status "Relay Status" [
			mode = "READWRITE",
			stateExtension = "&serviceId=urn:upnp-org:serviceId:SwitchPower1&id=variableget&Variable=Status",
			commandExtension = "&serviceId=urn:upnp-org:serviceId:SwitchPower1&id=action&action=SetTarget&newTargetValue=%2$s",
			onValue = "1",
			offValue = "0"
		]
		Type string: CommFailure "Comm Failure" [
			mode = "READONLY",
			stateExtension = "&serviceId=urn:micasaverde-com:serviceId:HaDevice1&id=variableget&Variable=CommFailure",
			stateTransformation = "MAP:vera2online.map"
		]
		Type string: ModeStatus "Mode Status" [
			mode = "READONLY",
			stateExtension = "&serviceId=urn:upnp-org:serviceId:HVAC_UserOperatingMode1&id=variableget&Variable=ModeStatus"
		]
		Type string: ModeState "Mode State" [
			mode = "READONLY",
			stateExtension = "&serviceId=urn:micasaverde-com:serviceId:HVAC_OperatingState1&id=variableget&Variable=ModeState"
		]
		Type datetime: LastUpdate "Last Update" [
			mode = "READONLY",
			stateExtension = "&serviceId=urn:micasaverde-com:serviceId:HaDevice1&id=variableget&Variable=LastUpdate"
		]
}

Items

//VERA
String strNetStatusText "Z-Wave Network Status" <status> ["Status"] { channel="http:url:vera:NetStatusText" }
String strVersionInfo "Z-Wave Version Info" <status> ["Status"] { channel="http:url:vera:VersionInfo" }
DateTime dtVeraLastUpdate "Vera Last Update" <calendar> ["Status"] { channel="http:url:vera:LastUpdate" }

//THERMOSTAT
Group gThermostat (gGroundHallway) ["HVAC"]
Number nCurrentSetpoint "Thermostat Setpoint" <temperature>  ["Setpoint","Temperature"] { channel="http:url:thermostat:CurrentSetpoint"}
Number nSetpointTarget "Thermostat Setpoint Target" <temperature> (gThermostat) ["Setpoint","Temperature"] { channel="http:url:thermostat:SetpointTarget", stateDescription=""[min="15", max="21", pattern="%.0f"], widget="oh-slider-card"[min=15, max=21, step=1, scale=true], listWidget="oh-slider-item"[min=15, max=21, step=1, scale=true] }
Number nCurrentTemperature "Thermostat Current Temperature" <temperature> (gThermostat) ["Measurement","Temperature"] { channel="http:url:thermostat:CurrentTemperature" }
Number nBatteryLevel "Thermostat Battery Level" <battery> (gThermostat) ["LowBattery"] { channel="http:url:thermostat:BatteryLevel" }
DateTime dtBatteryDate "Thermostat Battery Date" <calendar> ["Status"] { channel="http:url:thermostat:BatteryDate" }
DateTime dtThermostatLastUpdate "Thermostat Last Update" <calendar> ["Status"] { channel="http:url:thermostat:LastUpdate" }
String strThermostatModeStatus "Thermostat Mode Status" <mode> ["Status"] { channel="http:url:thermostat:ModeStatus" }
String strThermostatCommFailure "Thermostat Comm Failure" <mode> ["Status"] { channel="http:url:thermostat:CommFailure" }

//RELAY
Switch sRelayStatus "Relay Status" <switch> ["Switch"] { channel="http:url:relay:Status" }
String strRelayCommFailure "Relay Comm Failure" <mode> ["Status"] { channel="http:url:relay:CommFailure" }
String strRelayModeStatus "Relay Mode Status" <mode> ["Status"] { channel="http:url:relay:ModeStatus" }
String strRelayModeState "Relay Mode State" <mode> ["Status"] { channel="http:url:relay:ModeState" }
DateTime dtRelayLastUpdate "Thermostat Last Update" <calendar> ["Status"] { channel="http:url:relay:LastUpdate" }

vera2online.map

0=Online
1=Offline
2=Offline
1 Like

Now we’re talking. I’m going to spin up an OH3 vm and try some of this.