Hooking up the UVR1611 via BLNET

Hey @krimskrams,
great to hear its working on your system :slight_smile: I never got rid of the delay (message) myself, so a) I don’t think it’s problematic and b) I can’t really help out further.

Hi @ebnerjoh
did you got the CMI to work? I am still struggling with the setup, when I include the blnet: part in my configuration.yaml HA will stall with 100% CPU usage telling me the integration blnet cannot coimplete setup.
Thanks, Christian

Hi @krimskrams,

I am doing it via node red and HTTP-Request:

http://192.168.1.19/INCLUDE/api.cgi?jsonnode=1&jsonparam=I,O,Na

This gives me back all neccessary information and I am parsing it in Node Red and sending to Home Assistant via MQTT.

Br,
Johannes

Hi @krimskrams

That still sounds troublesome. Do this still occur? Any updates on this? Is it possible to access the CMI/BLNet interface using the exact IP you provide for your setup (just a wild guess)? I am not sure how exactly a complete stall might be caused during setup.

Honestly I did not further experiment with the integration of the CMI / UVR1611 into HA as I had no idea where / what to change.
The CMI itself does work, I have the UVR1611 Data Logger installed and it works perfectly.
And with the answer from @ebnerjoh I assume your code works with the BLnet but there are some differences to the CMI.

Alright. I do not have access to a CMI bridge so unfortunately I can’t help with it. Do note that I have also written a tool to integrate the UVR1611 Data Logger into home assistant - the tool is rather old though and may not work seemlessly anymore with the newest version of home assistant. It might be a starting point to get such an integration working again though.

@nielstron - Thank you for your very nice piece of work !
Just started integration your “blnet” component to a new HA installation ( 0.118.) - python venv type installation. This device (and your work) is my real motivation to start with HA!

after I installed the PyBLNET python library and adding the files from your gitbhub repo
my configuraiton was able to start with the “blnet” components,

but when enabling “use_ta true” I get following errors: I assume something with the data ( speed sensors) I got back from my ( OLD) BLNET - Firmware version 2.19 - is different as your development environment

Traceback (most recent call last):
  File "/home/homeassistant/lib/python3.8/site-packages/homeassistant/setup.py", line 213, in _async_setup_component
    result = await task
  File "/usr/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/homeassistant/.homeassistant/custom_components/blnet/__init__.py", line 103, in setup
    data = fetch_data()
  File "/home/homeassistant/.homeassistant/custom_components/blnet/__init__.py", line 99, in fetch_data
    return hass.data["DATA_{}".format(DOMAIN)].update()
  File "/home/homeassistant/.homeassistant/custom_components/blnet/__init__.py", line 147, in update
    data = self.blnet.fetch(self.node)
  File "/home/homeassistant/lib/python3.8/site-packages/pyblnet/blnet.py", line 90, in fetch
    direct = self.blnet_direct.get_latest(self.max_retries)[0]
  File "/home/homeassistant/lib/python3.8/site-packages/pyblnet/blnet_conn.py", line 328, in get_latest
    frames.update(self._split_latest(data, frame))
  File "/home/homeassistant/lib/python3.8/site-packages/pyblnet/blnet_conn.py", line 350, in _split_latest
    frames[frame] = BLNETParser(data[1:LATEST_SIZE + 1])
  File "/home/homeassistant/lib/python3.8/site-packages/pyblnet/blnet_parser.py", line 75, in __init__
    self.speed[channel + 1] = round(
TypeError: type NoneType doesn't define __round__ method

Any ideas ?

Hi @mahomh ,
Great to hear you have some use for the component!
The “use_ta” option (using BLNET-Direct) is not tested and likely not properly working at all as of now. The blnet component should work fine without it though :slight_smile:

Hi @nielstron ,
Thank you for your fast reply !
To understand it correctly - the “use_ta” option enables the direct communication via (default) port 40000 ? And there are no more features missing without that ?
But I do not see any componnet/entity in the UI.

Sorry to ask ( as I am new to HA) - I do not see in your example configuration.yaml, how to display the values and make switches visable - Can you give me some hints ?
Thanks, Martin

@martinh All features are available if the web-login worked correctly. Components should show up to be available automatically (not sure how this is handled in newer versions of HA, they used to just pop up on your main screen but I guess they do not anymore).

To see if there were any issues connecting try checking the logs of home assistant. Please do not refrain from contacting me if there are any bugs.

@nielstron great work!
I managed to integrate my uvr1611. I have one question: is it possible to see the current state of automated switches? I see if a digital switch is set to automated, the corresponding manual switch is always off. In the web frontend of the bootloader I see „AUTO/AUS“ and „AUTO/EIN“, regarding to the current state. I would like to set up an automation quering the state of „Anforderung Pelletkessel“ to check running out of pellets.

Regards and a happy new year

Georg

@nielstron
Since I had no experience with python and HA yet I needed some time to find the solution myself.
I changed the “switch.py” so that the icons show correct state.


I also added “mode” to the automatic switches as “EIN” or “AUS” and a new attribute “fullmode” to both switch types.

A bit tricky still is that there is no immediate update of the state if you change a switch. Maybe I’ll find out that later. This is my version:

"""
Connect to a BL-NET via it's web interface and read and write data

Switch to control digital outputs
"""
import logging

from homeassistant.const import (
    STATE_UNKNOWN)
from homeassistant.components.switch import SwitchDevice

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'blnet'

MODE = 'mode'
FULLMODE = 'fullmode'
FRIENDLY_NAME = 'friendly_name'


def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the BLNET component"""

    if discovery_info is None:
        _LOGGER.error("No BL-Net communication configured")
        return False

    switch_id = discovery_info['id']
    blnet_id = discovery_info['name']
    comm = hass.data['DATA_{}'.format(DOMAIN)]

    add_devices([BLNETSwitch(switch_id, blnet_id, comm),
                 BLNETModeSwitch(switch_id, blnet_id, comm)], True)
    return True


class BLNETSwitch(SwitchDevice):
    """
    Representation of a switch that toggles a digital output of the UVR1611.
    """

    def __init__(self, switch_id, blnet_id, comm):
        """Initialize the switch."""
        self._blnet_id = blnet_id
        self._id = switch_id
        self.communication = comm
        self._name = blnet_id
        self._friendly_name = blnet_id
        self._state = STATE_UNKNOWN
        self._assumed_state = True
        self._icon = None
        self._mode = STATE_UNKNOWN
        self._fullmode = STATE_UNKNOWN
        self._last_updated = None
        self._is_standby = None

    def update(self):
        """Get the latest data from communication device """
        # check if new data has arrived
        last_blnet_update = self.communication.last_updated()

        if last_blnet_update == self._last_updated:
            return

        sensor_data = self.communication.data.get(self._blnet_id)

        if sensor_data is None:
            return

        self._friendly_name = sensor_data.get('friendly_name')
        if sensor_data.get('value') == 'EIN':
            self._state = 'on'
            if sensor_data.get('mode') == 'AUTO':
                self._icon = 'mdi:cog-outline'
            else:
                self._icon = 'mdi:cog'
        # Nonautomated switch, toggled off => switch off
        else:
            self._state = 'off'
            if sensor_data.get('mode') == 'AUTO':
                self._icon = 'mdi:cog-off-outline'
            else:
                self._icon = 'mdi:cog-off'

        self._mode = sensor_data.get('mode')
        self._fullmode = sensor_data.get('mode') + '/' + sensor_data.get('value')
        self._last_updated = last_blnet_update
        self._assumed_state = False

    @property
    def name(self):
        """Return the name of the switch."""
        return self._name

    @property
    def state(self):
        """Return the state of the device."""
        return self._state

    @property
    def icon(self):
        """Return the state of the device."""
        return self._icon

    @property
    def device_state_attributes(self):
        """Return the state attributes of the device."""
        attrs = {}

        attrs[MODE] = self._mode
        attrs[FULLMODE] = self._fullmode
        attrs[FRIENDLY_NAME] = self._friendly_name
        return attrs

    @property
    def is_on(self):
        """Return true if device is on."""
        return self._state

    def turn_on(self, **kwargs):
        """Turn the device on."""
        if self._mode != 'AUTO':
            self.communication.turn_on(self._id)
            self._state = 'on'
            self._assumed_state = True

    def turn_off(self, **kwargs):
        """Turn the device off."""
        if self._mode != 'AUTO':
            self.communication.turn_off(self._id)
            self._state = 'off'
            self._assumed_state = True

    @property
    def assumed_state(self)->bool:
        return self._assumed_state

class BLNETModeSwitch(SwitchDevice):
    """
    Representation of a switch that toggles the operation mode
    of a digital output of the UVR1611. On means automated
    """

    def __init__(self, switch_id, blnet_id, comm):
        """Initialize the switch."""
        self._blnet_id = blnet_id
        self._id = switch_id
        self.communication = comm
        self._name = '{} automated'.format(blnet_id)
        self._friendly_name = blnet_id
        self._state = STATE_UNKNOWN
        self._activation_state = self._state
        self._assumed_state = True
        self._mode = STATE_UNKNOWN
        self._fullmode = STATE_UNKNOWN
        self._icon = None
        self._last_updated = None

    def update(self):
        """Get the latest data from communication device """
        # check if new data has arrived
        last_blnet_update = self.communication.last_updated()

        if last_blnet_update == self._last_updated:
            return

        sensor_data = self.communication.data.get(self._blnet_id)

        if sensor_data is None:
            return

        self._friendly_name = "{} automated".format(
            sensor_data.get('friendly_name'))
        if sensor_data.get('mode') == 'HAND':
            self._state = 'off'
            if sensor_data.get('value') == 'EIN':
                self._icon = 'mdi:cog-outline'
            else:
                self._icon = 'mdi:cog-off-outline'
            self._mode = 'HAND'
        else:
            self._state = 'on'
            if sensor_data.get('value') == 'EIN':
                self._mode = 'EIN'
                self._icon = 'mdi:cog'
            elif sensor_data.get('value') == 'AUS':
                self._mode = 'AUS'
                self._icon = 'mdi:cog-off'
            else:
                self._mode = 'unbekannt'
                self._icon = 'mdi:cog-refresh-outline'
        
        self._activation_state = sensor_data.get('value')

        self._fullmode = sensor_data.get('mode') + '/' + sensor_data.get('value')
        self._last_updated = last_blnet_update
        self._assumed_state = False

    @property
    def name(self):
        """Return the name of the switch."""
        return self._name

    @property
    def state(self):
        """Return the state of the device."""
        return self._state

    @property
    def icon(self):
        """Return the state of the device."""
        return self._icon

    @property
    def device_state_attributes(self):
        """Return the state attributes of the device."""
        attrs = {}
        attrs[MODE] = self._mode
        attrs[FULLMODE] = self._fullmode
        attrs[FRIENDLY_NAME] = self._friendly_name
        return attrs

    @property
    def is_on(self):
        """Return true if device is on."""
        return self._state

    def turn_on(self, **kwargs):
        """Turn the device on."""
        self.communication.turn_auto(self._id)
        self._state = 'on'
        self._assumed_state = True

    def turn_off(self, **kwargs):
        """Turn the device off."""
        if self._activation_state == 1:
            self.communication.turn_on(self._id)
        else:
            self.communication.turn_off(self._id)
        self._state = 'off'
        self._assumed_state = True

    @property
    def assumed_state(self)->bool:
        return self._assumed_state

thanks for your work and regards

Georg

blnet_details

Hi @bulli,

that looks really nice! I thought I had already implemented the actual state to be reflected somehow, however I am not sure whether or where it was implemented.

Do you mind making your changes a pull request at the repository of this component, ha_blnet? Then I can have a closer look and integrate the changes :slight_smile:

Best regards, Niels

Hi @nielstron

OK, got the current version from GitHub (seems I used an older one), made my changes and created a pull request

Georg

@bulli - Thank you for your update for “BLNET” - Now I see the status of my heating/BLNET digital sensor - it is already showing up on my dashboard !

@nielstron - I really appreciate your integration of @bulli’s updates - I verified the problem with temperatures/values below 0 with the latest source:

Sorry, but senors are still missing if their temperature value is below 0 degrees- if the value goes above 0 the sensor is listed again - see below - “sensor 1” is outside temperature

( I checked all the files from the “master” repository. including “pyblnet”)

2021-01-07 04:29:32 INFO (SyncWorker_5) [custom_components.blnet] Collecting data...
2021-01-07 04:29:32 INFO (SyncWorker_5) [custom_components.blnet] Checking for new sensors...
2021-01-07 04:33:29 INFO (SyncWorker_15) [custom_components.blnet] Collecting data...
2021-01-07 04:33:29 INFO (SyncWorker_15) [custom_components.blnet] Checking for new sensors...
2021-01-07 04:33:29 INFO (SyncWorker_15) [custom_components.blnet] Discovered analog sensor 2 in use, adding
2021-01-07 04:33:29 INFO (SyncWorker_15) [custom_components.blnet] Discovered analog sensor 3 in use, adding
2021-01-07 04:33:29 INFO (SyncWorker_15) [custom_components.blnet] Discovered analog sensor 4 in use, adding
2021-01-07 04:33:29 INFO (SyncWorker_15) [custom_components.blnet] Discovered analog sensor 5 in use, adding
2021-01-07 04:33:29 INFO (SyncWorker_15) [custom_components.blnet] Discovered analog sensor 6 in use, adding
2021-01-07 04:33:29 INFO (SyncWorker_15) [custom_components.blnet] Discovered analog sensor 7 in use, adding

if temperature increases sensor 1 “appears”:

2021-01-07 09:49:29 INFO (SyncWorker_6) [custom_components.blnet] Collecting data...
2021-01-07 09:49:29 INFO (SyncWorker_6) [custom_components.blnet] Checking for new sensors...
2021-01-07 09:49:29 INFO (SyncWorker_6) [custom_components.blnet] Discovered analog sensor 1 in use, adding
2021-01-07 09:49:29 INFO (MainThread) [homeassistant.components.sensor] Setting up sensor.blnet
2021-01-07 09:49:29 INFO (SyncWorker_6) [custom_components.blnet] Added overall 1 sensors

Can you please have a look at this ? Thank you

Thanks @mahomh for the investigation.

To fix this I need the HTML source of the BLNET Webinterface when reading the digital values.
Of course only at the point where any digital value is negative.

A short guideline how to accomplish this:

  • Log in to the web interface
  • navigate to the digital values (sth like Menu->Digital Values)
  • right-click -> show source

If there are any issues let me know :slight_smile:

@nielstron I didn’t mention this yet, but I just have the same issue as @mahomh.
HTML-Snipplet of negative value “- 1,2 °C” on page 580500.htm:

                    <div class="c" style="width:21em;">
                         &nbsp;1:&nbsp;TKollektor
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;1,2 &deg;C &nbsp;&nbsp;PAR?
                        <span class="pf">
                            <button type="button" onclick="document.location.href='580C01.htm'">
                                <=
                            </button>
                        </span>
                        <br>
                        &nbsp;2:&nbsp;Puffer1oben
                        <br>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;49,8 &deg;C &nbsp;&nbsp;PAR?
                        <span class="pf">
                            <button type="button" onclick="document.location.href='580C02.htm'">
                                <=
                            </button>
                        </span>
                        <br>

regards
Georg

@bulli Thanks, that’s exactly what I needed. The change should be up soon.

It is working now also with negative values
Thank you @nielstron

1 Like