Giter Site home page Giter Site logo

linak-2-mqtt's Introduction

Linak2MQTT

Credits: This project wouldn't have been possible without the incredible work done by @rhyst on the idasen-controller project ❤️. Don't forget to give him a ⭐!

Table of content

Setup

Prerequisites

Bluetooth initial setup

Your host must have your desk paired and trusted as a bluetooth device first.
The reason for that being: When starting out the docker we give access to the bluetooth dongle and all the config. This way the docker image is able to connect to the desk straight away.

From the host:

  • bluetoothctl
  • [bluetooth]# power off
  • [bluetooth]# power on
  • Press the button on the desk for 2 or 3s till the LED is blinking
  • [bluetooth]# scan on

Example of output while the scan is on

Discovery started
[CHG] Controller XX:XX:XX:XX:XX:XX Discovering: yes
[CHG] Device XX:XX:XX:XX:XX:XX RSSI: -83
[CHG] Device XX:XX:XX:XX:XX:XX RSSI: -71
[NEW] Device XX:XX:XX:XX:XX:XX Desk 7734 <-- notice the [NEW] here
[CHG] Device XX:XX:XX:XX:XX:XX RSSI: -75
[CHG] Device XX:XX:XX:XX:XX:XX RSSI: -95
  • [bluetooth]# scan off
  • [bluetooth]# trust XX:XX:XX:XX:XX:XX
  • [bluetooth]# pair XX:XX:XX:XX:XX:XX

And from here you should see the prompt like this [Desk 7734]# meaning you're connected to the desk, at which point you must disconnect from it by typing [Desk 7734]# disconnect

All the configuration on the side of the host is now done and you should not have to manipulate anything here anymore.

Run the docker image

The docker image will connect to your desk and interact with it through MQTT so that you can interact with it the way you want.

Before building and launching it:

  • Copy linak-2-mqtt.env.template into a new file called linak-2-mqtt.env and update the values
  • Copy linak-config.yaml.template into a new file called linak-config.yaml and update the values (at least the mac address)

Then:

  • docker build -t linak-2-mqtt .
  • docker run -it --rm --privileged -v /var/run/dbus:/var/run/dbus -v $(pwd)/linak-2-mqtt.env:/.env -v $(pwd)/linak-config.yaml:/linak-config.yaml linak-2-mqtt

MQTT interactions

You can listen to:

  • linak-2-mqtt/desk-height-updated which will pass the desk height as payload in cm

You publish to:

  • linak-2-mqtt/set-desk-height pass the desk height you wish in cm
  • linak-2-mqtt/toggle-desk-position no payload needed

Home Assistant integrations

The MQTT API ensure you can build any kind of integration you'd like. Speaking for myself, I've chosen to use Home Assistant. In this seection I'll explain how to specifically integrate your desk in Home Assistant and give some examples of automations.

Lovelace linak-desk-card

@IhorSyerkov has built a great (interactive) Lovelace card:

Desk in sitting position Desk in standing position
Desk in sitting position Desk in standing position

This was originally built to integrate with ESPHome idasen-desk-controller (see linak-desk-card's documentation), but I didn't want to have using another device hence why I built my own solution.

That's why we've got a little bit of configuration to make on Home Assistant in order to have the card working properly.

  • Start by following linak-desk-card's README and install the card using HACS
  • Open your HA config file /config/configuration.yaml and either create or update your sensor and binary_sensor lists with the following:
mqtt:
  sensor:
    - name: linak_desk_height
      state_topic: 'linak-2-mqtt/desk-relative-height-updated'
  binary_sensor:
    - name: is_desk_available
      state_topic: 'linak-2-mqtt/desk-relative-height-updated'
      off_delay: 100
      value_template: "{{ 'online' }}"
      payload_on: 'online'
      payload_off: 'offline'

On your dashboard, we'll now create a new card:

type: custom:linak-desk-card
min_height: 62
max_height: 127
presets:
  - label: Stand
    target: 120
  - label: Sit
    target: 73
name: Desk
height_sensor: sensor.linak_desk_height
connection_sensor: binary_sensor.is_desk_available
# @todo not implemented because I'm unsure what that'll change and it's not a priority for now
# moving_sensor: binary_sensor.is_desk_moving
desk: cover.desk

Important note:

Make sure the config above matches:

  • The one defined in linak-2-mqtt.env that you're mounting on the docker container for:
    • min_height / DESK_LOWEST_HEIGHT_CM
    • max_height / DESK_HIGHEST_HEIGHT_CM
  • The one defined in linak-config.yaml that you're mounting on the docker container:
  • presets[label="Stand"].target / stand_height
  • presets[label="Sit"].target / sit_height

This is slightly annoying to have some configuration duplicated but I haven't found a better option for now and it's not something you'll need to edit all the time.

Everything we did so far was in order to get the correct height displayed on the desk card. Now lets hook the 2 buttons stand and sit so we're able to control the desk from that card as well.

In order to do that, you'll need to create the following automation:

alias: 'Desk: Bind cover.set_cover_position to MQTT'
description: ''
trigger:
  - platform: event
    event_type: call_service
    event_data:
      domain: cover
      service: set_cover_position
condition: []
action:
  - service: mqtt.publish
    data:
      topic: linak-2-mqtt/set-desk-height
      payload_template: >
        {% set service_data =
        trigger.event.as_dict().get('data').get('service_data') %} {{
        ((service_data.get('position') * (127 - 62) / 100) + 62) | round(0) }}
mode: single

Note: Same here, it'd be nice to get the 127 (max height) and 62 (min height) from the card config if possible but I haven't done it for now.

Toggle the current position between sit and up using an NFC tag

alias: 'Tag Desk: Toggle desk position'
description: ''
trigger:
  - platform: tag
    tag_id: YOUR-TAG-ID-HERE
condition: []
action:
  - service: mqtt.publish
    data:
      topic: linak-2-mqtt/toggle-desk-position
mode: single

Automatically put the desk up for daily standup meetings

Last but not least, if you have some daily standup meeting for example, you could automatically put the desk up at that time if:

  • It's a work day
  • You're home
  • A manual input boolean is currently on (in case you ever want to turn it off simply)

All this should let you avoid unnecessary triggers.

alias: 'Desk: Standing position at standup time on workday if I am home'
description: ''
trigger:
  - platform: time
    at: '10:59:00'
condition:
  - condition: zone
    entity_id: device_tracker.PHONE_TRACKER_HERE
    zone: zone.home
  - condition: state
    entity_id: binary_sensor.workday_sensor
    state: 'on'
  - condition: state
    entity_id: input_boolean.shoulddeskgostandingpositiononworkdaysifiamhome
    state: 'on'
action:
  - service: mqtt.publish
    data:
      topic: linak-2-mqtt/set-desk-height
      payload: '120'
mode: single

Don't forget to create both:

  • the input_boolean helper
  • the workday_sensor if you don't have one already. Example:
binary_sensor:
  # ... your other binary sensors
  - platform: workday
    name: workday_sensor
    country: FR
    workdays: [mon, tue, wed, thu, fri]
    excludes: [sat, sun]

Here's an example of complete dashboard:

Desk dashboard

- theme: Backend-selected
  title: Office
  path: office
  badges: []
  cards:
    - type: custom:linak-desk-card
      min_height: 62
      max_height: 127
      presets:
        - label: Stand
          target: 120
        - label: Sit
          target: 73
      name: Desk
      height_sensor: sensor.linak_desk_height
      connection_sensor: binary_sensor.is_desk_available
      moving_sensor: binary_sensor.linak_desk_moving
      desk: cover.desk
    - type: entities
      entities:
        - entity: input_boolean.shoulddeskgostandingpositiononworkdaysifiamhome
          name: Automatically go up at standup time?
      title: Desk
      show_header_toggle: false
      state_color: false
    - type: entities
      entities:
        - entity: binary_sensor.workday_sensor
          name: Is today a work day?
          icon: mdi:office-building
      state_color: false

Troubleshooting issues

If the logs show

[debug] Connected
starting idasen server...
Connecting
Connecting failed
Device with address XX:XX:XX:XX:XX:XX was not found.

Either:

  • You've never connected the desk in bluetooth. Refer to Bluetooth initial setup
  • Another device is already connected to the desk. Check first on your host machine if bluetoothctl shows [bluetooth]# or something like [Desk 7734]#. If it's [bluetooth] it means it's fine, the host is not connected to it (but you'll have to check your other devices like phone etc...), if it shows [Desk 7734]# the fix is easy, from here type disconnect: [Desk 7734]# disconnect and it should go back to [bluetooth]#. Stop and start again the docker image, everything should be fine
  • Something has just gone wrong and none of the above fixes it. Try first on the host to
    • Turn the bluetooth on and off
      • bluetoothctl
      • [bluetooth]# power off
      • [bluetooth]# power on
    • Connect to the device again [bluetooth]# connect XX:XX:XX:XX:XX:XX
    • If that works, disconnect from it straight away ([Desk 7734]# disconnect) and relaunch the docker image
    • If that doesn't work, you may need to remove the device and make sure that you: Find it, trust it, pair it (in this order)
      • [bluetooth]# remove XX:XX:XX:XX:XX:XX
      • From here follow again the Bluetooth initial setup section

Useful links

linak-2-mqtt's People

Contributors

ap0ph1s-w4ite avatar datbilling avatar ipatalas avatar maxime1992 avatar sobuno avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

linak-2-mqtt's Issues

Desk stutters as it moves

Hello! I've been trying out this program.
Unfortunately when I move the desk, it starts and stops several times until it reaches the desired height.
Logs don't really show anything, though there's an error at the end, I don't think it's related. Any ideas? Is there any way in which I can help?
This doesn't happen when using the Linak app.

linak-2-mqtt     | client message. Topic "linak-2-mqtt/set-desk-height", value: 97                                                                                                                    
linak-2-mqtt     | Attempt to move desk to 97cm                                                                                                                                                       
linak-2-mqtt     | Received command                                                                                                                                                                   
linak-2-mqtt     |                                                                                                                                                                                    
linak-2-mqtt     | Height:  950mm                                                                                                                                                                     
linak-2-mqtt     | Moving to height: 970                                                                                                                                                              
linak-2-mqtt     |                                                                                                                                                                                    
linak-2-mqtt     | returned 950       
linak-2-mqtt     | publishing updated height { absolute: 95, 'process.env.DESK_LOWEST_HEIGHT_CM':                                                                                                    
62, relative: 33 }                                                                                                                                              
linak-2-mqtt     | Height:  957mm Speed: 37mm/s                                                                                                                                                       
linak-2-mqtt     |                                                                                                                                               
linak-2-mqtt     | returned 957                                                                                                                                                                      
linak-2-mqtt     | publishing updated height { absolute: 96, 'process.env.DESK_LOWEST_HEIGHT_CM':                                                                                                     
62, relative: 34 }                                                                                                                                                                               
linak-2-mqtt     | Height:  970mm Speed:  0mm/s                                                                                                                                                  
linak-2-mqtt     |                                                                                                                                                                                 
linak-2-mqtt     | returned 970                                                                                                                                                                      
linak-2-mqtt     | publishing updated height { absolute: 97, 'process.env.DESK_LOWEST_HEIGHT_CM':                                                                                                    
62, relative: 35 }                                                                                                                                                                                
linak-2-mqtt     | Error handling request                                                                                                                                                             
linak-2-mqtt     | Traceback (most recent call last):                                                                                                                                                 
linak-2-mqtt     |   File "/usr/local/lib/python3.8/dist-packages/aiohttp/web_protocol.py", line 4                                                                                                    
35, in _handle_request                                                                                                                                          
linak-2-mqtt     |     resp = await request_handler(request)                                                                                                                                          
linak-2-mqtt     |   File "/usr/local/lib/python3.8/dist-packages/aiohttp/web_app.py", line 504, i                                                                                                    
n _handle                                                                                                                                                                                             
linak-2-mqtt     |     resp = await handler(request)                                                                                                                                                  
linak-2-mqtt     |   File "/usr/local/lib/python3.8/dist-packages/idasen_controller/main.py", line                                                                                                    
 433, in run_forwarded_command                                                                                                                                                 
linak-2-mqtt     |     await run_command(client, merged_config, log)                                                                                                                                  
linak-2-mqtt     |   File "/usr/local/lib/python3.8/dist-packages/idasen_controller/main.py", line                                                                                                    
 359, in run_command                                                                                                                                             
linak-2-mqtt     |     await move_to(client, target, log=log)                                                                                                                                         
linak-2-mqtt     |   File "/usr/local/lib/python3.8/dist-packages/idasen_controller/main.py", line                                                                                                    
 294, in move_to                                                                                                                                                 
linak-2-mqtt     |     await unsubscribe(client, UUID_HEIGHT)                                                                                                                                         
linak-2-mqtt     |   File "/usr/local/lib/python3.8/dist-packages/idasen_controller/main.py", line                                                                                                    
 263, in unsubscribe                                                                                                                                                                                  
linak-2-mqtt     |     await client.stop_notify(uuid)                                                                                                                                                 
linak-2-mqtt     |   File "/usr/local/lib/python3.8/dist-packages/bleak/backends/bluezdbus/client.                                                                                                    
py", line 963, in stop_notify                                                                                                                                                                         
linak-2-mqtt     |     assert_reply(reply)                                                                                                                                                            
linak-2-mqtt     |   File "/usr/local/lib/python3.8/dist-packages/bleak/backends/bluezdbus/utils.p                                                                                                    
y", line 23, in assert_reply                                                                                                                                                                          
linak-2-mqtt     |     raise BleakDBusError(reply.error_name, reply.body)                                                                                                                             
linak-2-mqtt     | bleak.exc.BleakDBusError: [org.bluez.Error.Failed] No notify session started                                                                                                       
linak-2-mqtt     |                                                                                                                                                                                    
linak-2-mqtt     | Ping to get the height and make sure the desk appears as connected             

Build wheel: finished with status 'error'

When I try to run the command docker build -t linak-2-mqtt . I am receiving the following wheel error.

pi@FermPi:~/linak-2-mqtt $ sudo docker build -t linak-2-mqtt .
Sending build context to Docker daemon  318.5kB
Step 1/18 : FROM ubuntu:focal
 ---> 0a13b0a84dab
Step 2/18 : RUN apt update -y && apt upgrade -y
 ---> Using cache
 ---> 4d0bee4cffbe
Step 3/18 : RUN apt install python3 python3-pip -y
 ---> Using cache
 ---> 1917ffb165c4
Step 4/18 : ENV TZ=Europe/Paris
 ---> Using cache
 ---> 656329445726
Step 5/18 : RUN ln -snf /usr/share/zoneinfo/$CONTAINER_TIMEZONE /etc/localtime && echo $CONTAINER_TIMEZONE > /etc/timezone
 ---> Using cache
 ---> d08d4c6d42ff
Step 6/18 : RUN apt install bluez -y
 ---> Using cache
 ---> 5800ee81ffa9
Step 7/18 : RUN apt install build-essential libglib2.0-dev libical-dev libreadline-dev libudev-dev libdbus-1-dev libdbus-glib-1-dev bluetooth libbluetooth-dev usbutils -y
 ---> Using cache
 ---> cdd90dea4bee
Step 8/18 : RUN pip3 install idasen-controller==2.0.1
 ---> Running in 16d47c4e0efd
Collecting idasen-controller==2.0.1
  Downloading idasen_controller-2.0.1-py3-none-any.whl (10 kB)
Collecting PyYAML<=6.0.0,>=5.4.1
  Downloading PyYAML-6.0.tar.gz (124 kB)
  Installing build dependencies: started
  Installing build dependencies: finished with status 'done'
  Getting requirements to build wheel: started
  Getting requirements to build wheel: finished with status 'error'
  ERROR: Command errored out with exit status 1:
   command: /usr/bin/python3 /tmp/tmpjprtw9xp get_requires_for_build_wheel /tmp/tmpnfgp2v_i
       cwd: /tmp/pip-install-n9vxfd6_/PyYAML
  Complete output (48 lines):
  running egg_info
  writing lib/PyYAML.egg-info/PKG-INFO
  writing dependency_links to lib/PyYAML.egg-info/dependency_links.txt
  writing top-level names to lib/PyYAML.egg-info/top_level.txt
  Traceback (most recent call last):
    File "/tmp/tmpjprtw9xp", line 280, in <module>
      main()
    File "/tmp/tmpjprtw9xp", line 263, in main
      json_out['return_val'] = hook(**hook_input['kwargs'])
    File "/tmp/tmpjprtw9xp", line 114, in get_requires_for_build_wheel
      return hook(config_settings)
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 325, in get_requires_for_build_wheel
      return self._get_build_requires(config_settings, requirements=['wheel'])
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 295, in _get_build_requires
      self.run_setup()
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/build_meta.py", line 311, in run_setup
      exec(code, locals())
    File "<string>", line 288, in <module>
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/__init__.py", line 104, in setup
      return distutils.core.setup(**attrs)
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/_distutils/core.py", line 184, in setup
      return run_commands(dist)
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/_distutils/core.py", line 200, in run_commands
      dist.run_commands()
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/_distutils/dist.py", line 969, in run_commands
      self.run_command(cmd)
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/dist.py", line 967, in run_command
      super().run_command(command)
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/_distutils/dist.py", line 988, in run_command
      cmd_obj.run()
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/command/egg_info.py", line 321, in run
      self.find_sources()
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/command/egg_info.py", line 329, in find_sources
      mm.run()
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/command/egg_info.py", line 550, in run
      self.add_defaults()
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/command/egg_info.py", line 588, in add_defaults
      sdist.add_defaults(self)
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/command/sdist.py", line 102, in add_defaults
      super().add_defaults()
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/_distutils/command/sdist.py", line 250, in add_defaults
      self._add_defaults_ext()
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/_distutils/command/sdist.py", line 335, in _add_defaults_ext
      self.filelist.extend(build_ext.get_source_files())
    File "<string>", line 204, in get_source_files
    File "/tmp/pip-build-env-5qjwrx6j/overlay/lib/python3.8/site-packages/setuptools/_distutils/cmd.py", line 107, in __getattr__
      raise AttributeError(attr)
  AttributeError: cython_sources
  ----------------------------------------
ERROR: Command errored out with exit status 1: /usr/bin/python3 /tmp/tmpjprtw9xp get_requires_for_build_wheel /tmp/tmpnfgp2v_i Check the logs for full command output.
The command '/bin/sh -c pip3 install idasen-controller==2.0.1' returned a non-zero code: 1

Up & down arrows not working

Hello, the arrows to move the desk up or down don't do anything when pressed.
Is this a bug or can this functionality be added please?

Error while running the system

Hi!

First of all I want to thank you for the work in this repo. I was looking for something like this, and it always amaze me how already someone somewhere is already done whatever I need.

I'm running the linak docker container on a raspberry pi 3b+ and I'm facing some issues. The plan was to put the docker command on crontab so, at every reboot the docker will run itself. I have achieved that by running this command:

@reboot sleep 60 & /usr/bin/docker run -i --rm --privileged -v /var/run/dbus:/var/run/dbus -v /home/pi/linak-2-mqtt/linak-2-mqtt.env:/.env -v /home/pi/linak-2-mqtt/linak-config.yaml:/linak-config.yaml linak-2-mqtt > /home/pi/crontablog/linak-2-mqtt.log 2>&1

Disclose of the oneliner code :

sleep 60 is needed to let the system wake and make every part accesible to the script. If not added, it fails.
needed to change the parameter -it to -i to fix "input device is not tty" Error.
Also, added full path to docker and folder storing the docker container files to avoid any issues.

/home/pi/crontablog/linak-2-mqtt.log 2>&1 store the log fron the crontab in the chosen path.

That seems to run ok.

The issue is that some times the desk seems to not move at all, after receiving the correct message on the topic. Here is a log example:

[debug] Connected
starting idasen server...
Connecting
Connected DF:75:F4:7D:80:E3

triggering watch..
Server listening

Received command

Height:  794mm

returned 794
publishing updated height { absolute: 79, 'process.env.DESK_LOWEST_HEIGHT_CM': 70, relative: 9 }
client message. Topic "linak-2-mqtt/set-desk-height", value: 113
Attempt to move desk to 113cm
Received command

Height:  794mm

returned 794
publishing updated height { absolute: 79, 'process.env.DESK_LOWEST_HEIGHT_CM': 70, relative: 9 }
Moving to height: 1130

Height:  794mm Speed:  0mm/s

returned 794
publishing updated height { absolute: 79, 'process.env.DESK_LOWEST_HEIGHT_CM': 70, relative: 9 }
Final height:  794mm (Target: 1130mm)

As you can see, the desk is connected and the desk is recieved the correct height information. After that, the message shows a speed of 0 mm/s. Which I think is the root of problem.

If I move the desk using the attached controller, the new height is displayed properly:

Height:  928mm

returned 928

I have confirmed that it's working after connecting it to the app, as recalled on this issue: rhyst/linak-controller#32

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.