Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v2] Initial release - simplify the repository #70

Merged
merged 39 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
28d2c5c
Move old documents to archive
iMicknl Oct 1, 2023
6303fa7
Add new files
iMicknl Oct 1, 2023
2747935
Dont spam the log with updates
iMicknl Nov 6, 2023
6a1da5d
Simplify desk YAML
iMicknl Nov 6, 2023
400116c
Update with components
iMicknl Nov 6, 2023
cd899c4
v2.1 try
iMicknl Nov 6, 2023
1e2891f
Tidy config file
jamesmyatt May 22, 2024
248fbb8
Improve README
jamesmyatt May 22, 2024
9931ca6
First try at height sensor component
jamesmyatt May 22, 2024
4e96fd5
Remove extra file
jamesmyatt May 23, 2024
c33e438
Merge pull request #84 from jamesmyatt/v2.2
iMicknl Jun 1, 2024
c369e39
Apply suggestions from code review
iMicknl Jun 7, 2024
41a07b2
Merge pull request #85 from iMicknl/v2.1
iMicknl Jun 7, 2024
f66701c
Add devcontainer and initial CI/CD + pre-commit configuration
iMicknl Jun 8, 2024
5bad540
Update GH Actions triggers
iMicknl Jun 8, 2024
6ed833f
Fix CI/CD
iMicknl Jun 8, 2024
8aea3bc
Add tests
iMicknl Jun 8, 2024
35e9cf9
Update test files
iMicknl Jun 8, 2024
4e212b0
Apply pre-commit on all files
iMicknl Jun 8, 2024
3fff038
Change encryption key to base64
iMicknl Jun 8, 2024
f17a71a
Update encryption key base64 to 32 bits
iMicknl Jun 8, 2024
e0c3667
Add validation step
iMicknl Jun 8, 2024
4f82920
Improve linting and validating strategy
iMicknl Jun 8, 2024
f3da259
Revert desk_height_sensor.cpp changes
iMicknl Jun 8, 2024
1f57297
Revert "Revert desk_height_sensor.cpp changes"
iMicknl Jun 8, 2024
c9bca29
Change byte to unsigned char
iMicknl Jun 10, 2024
79cd188
Fix config
jamesmyatt Jun 15, 2024
0bf1520
Use uint8_t and read_byte
jamesmyatt Jun 15, 2024
939c2b0
Merge pull request #88 from jamesmyatt/fix-config
iMicknl Jun 15, 2024
d21b9fa
Fix
jamesmyatt Jun 15, 2024
3971a7b
More uint8_t
jamesmyatt Jun 15, 2024
b87162a
linting fixes
jamesmyatt Jun 15, 2024
772e7d5
More uint8_t
jamesmyatt Jun 15, 2024
f8a9913
Merge pull request #89 from jamesmyatt/2.4
iMicknl Jun 15, 2024
568df69
Update devcontainer
iMicknl Jun 15, 2024
137edb0
Change CI+devcontainer to Python 3.11
iMicknl Jun 15, 2024
2ea9c02
Merge pull request #90 from iMicknl/v2.4
iMicknl Jun 15, 2024
2a97519
Fix/clarify pin-out
jamesmyatt Jul 14, 2024
2ce9bdd
Merge pull request #91 from jamesmyatt/fix-docs
iMicknl Jul 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
"name": "Python 3",
"image": "mcr.microsoft.com/devcontainers/python:1-3.11-bookworm",

// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "pip3 install --user -r requirements.txt && pre-commit install",

// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"GitHub.copilot-chat",
"ESPHome.esphome-vscode",
"redhat.vscode-yaml",
"ms-python.python",
"ms-vscode.cpptools",
"ms-vscode.cpptools-extension-pack"
]
}
}

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @iMicknl
13 changes: 13 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: 2
updates:
- package-ecosystem: "devcontainers"
directory: "/"
schedule:
interval: daily
time: "08:00"

- package-ecosystem: pip
directory: "/"
schedule:
interval: "daily"
time: "08:00"
3 changes: 3 additions & 0 deletions .github/workflows/build-and-publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# uses: esphome/build-action@v1
# with:
# yaml_file: my_configuration.yaml
29 changes: 29 additions & 0 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
pull_request:
push:
branches: [main]

jobs:
pre-commit:
name: "Linting and formatting"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"

- name: "Install Python dependencies"
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

- uses: pre-commit/[email protected]

# - uses: pre-commit-ci/[email protected]
# if: always()
37 changes: 37 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Test ESPHome configuration files using local components
name: Compile and validate YAML configuration

on:
pull_request:
push:
branches: [main]

jobs:
tests:
name: "${{ matrix.version }}"
runs-on: "ubuntu-latest"

strategy:
fail-fast: false
matrix:
version: ["esp32", "esp8266", "esp32-passthrough", "esp8266-passthrough"]

steps:
- uses: "actions/checkout@v4"

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"

- name: "Install Python dependencies"
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

- name: "Validate ${{ matrix.version }}"
run: esphome config tests/office-desk-${{ matrix.version }}.yaml

- name: "Compile ${{ matrix.version }}"
run: esphome compile tests/office-desk-${{ matrix.version }}.yaml
37 changes: 37 additions & 0 deletions .github/workflows/validate-packages.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Validate ESPHome packages using latest published components
name: Validate ESPHome packages

on:
pull_request:
push:
branches: [main]

jobs:
tests:
name: "${{ matrix.version }}"
runs-on: "ubuntu-latest"

strategy:
fail-fast: false
matrix:
version: ["esp32"]

steps:
- uses: "actions/checkout@v4"

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"

- name: "Install Python dependencies"
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

- name: "Validate ${{ matrix.version }}"
run: esphome config tests/office-desk-${{ matrix.version }}.yaml

- name: "Compile ${{ matrix.version }}"
run: esphome compile tests/office-desk-${{ matrix.version }}.yaml
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
venv
.esphome
.esphome

*.pyc
__pycache__/
21 changes: 21 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-yaml
args: ['--unsafe'] # required for !secret
- id: trailing-whitespace
- id: end-of-file-fixer

# - repo: https://github.com/pocc/pre-commit-hooks
# rev: v1.3.5
# hooks:
# - id: clang-format
# - id: clang-tidy
# - id: cppcheck
# - id: cpplint
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v18.1.6
hooks:
- id: clang-format
types_or: [c++, c, cuda]
101 changes: 57 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ This repository will help you to connect your desk to the internet via the seria

> Use the information in this repository at your own risk and with caution. Tinkering with electronics always has risks.

| Name | Description |
| ------------------------------------- | -------------------------------------------------------------------------- |
| [Arduino](packages/arduino) | Custom code to control your desk via an ESP32/ESP8266 module via MQTT. |
| [ESPHome](packages/esphome) | Control your desk via an ESP32/ESP8266 module connected to Home Assistant. |
| [Raspberry Pi](packages/raspberry-pi) | Custom code to control your desk via a Raspberry Pi via Python. |
| Name | Description |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
| [ESPHome](packages/office-desk.yaml) | Control your desk via an ESP32 module connected to Home Assistant. Can be adapted to ESP8266 or other ESP32 variant. |

The V1 packages, including the Arduino and Raspberry Pi ones, can be found in the `archive` directory.

For more packaged solutions, see [similar projects](#similar-projects--research). Pull requests are welcome.

Expand All @@ -30,10 +30,15 @@ If you are interested in the internals of the LoctecMotion desk system, have a l

At the time of writing, LoctekMotion sells [11 different control panels](https://www.loctekmotion.com/product/control-panel/). The features can differ per model, but it looks like the serial interface is pretty similar for the more advanced models.

The tables below will show a mapping of the RJ45 pinout to the pinout used by the control panel. Please note that all RJ45 pins are described in the following way;
The tables below will show a mapping of the RJ45 pinout to the pinout used by the control panel. Please note that all RJ45 pins are described in the following way:

![RJ-45 connector layout](images/RJ-45_connector.jpg)

The most common [color convention](https://www.showmecables.com/blog/post/rj45-pinout)
for wiring RJ45 for network cables is:

![RJ45 T568B colors](images/RJ45-Pinout-T568B.jpg)

In order to connect the control box to a Raspberry Pi and ESP32/ESP8266 chip I used a [RJ45 to RS232 adapter](https://www.allekabels.nl/rs232-kabel/4568/1041186/rj45-naar-rs232.html) with DuPont cables (jump wires), but you simply can cut and split an ethernet cable as well.

#### Supported Control Panels
Expand All @@ -49,70 +54,73 @@ In order to connect the control box to a Raspberry Pi and ESP32/ESP8266 chip I u
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->

If your control panel is missing, feel free to [create an issue](https://github.com/iMicknl/LoctekMotion_IoT/issues/new) to discuss the possibilities or create a PR to add your research to this overview.
If your control panel is missing, feel free to [create an issue](https://github.com/iMicknl/LoctekMotion_IoT/issues/new) to discuss the possibilities or create a PR to add your research to this overview.

#### HS13B-1

- **Desk model**: Flexispot E7
- **Tested with control box**: CB38M2J(IB)-1
- **Source**: Printed on the PCB of the control box.

| RJ45 pin | Name | Original Cable Color | Ethernet cable color (T568B) |
| -------- | ---------- | -------------------- | ---------------------------- |
| 8 | RESET | Brown | White-Orange |
| 7 | SWIM | White | Orange |
| 6 | EMPTY | Purple | White-Green |
| 5 | PIN 20 | Red | Blue |
| 4 | RX | Green | White-Blue |
| 3 | TX | Black | Green |
| 2 | GND | Blue | White-Brown |
| 1 | +5V (VDD) | Yellow | Brown |

Note that RX and TX is defined like this on receiver (control panel) side. So RX can be used to receive data, TX to send data.
| 1 | RESET | Brown | White-Orange |
| 2 | SWIM | White | Orange |
| 3 | EMPTY | Purple | White-Green |
| 4 | PIN 20 | Red | Blue |
| 5 | RX | Green | White-Blue |
| 6 | TX | Black | Green |
| 7 | GND | Blue | White-Brown |
| 8 | +5V (VDD) | Yellow | Brown |

Note that RX and TX is defined like this on receiver (control panel) side.
So the custom controller also uses RX to receive data and TX to send data.

#### HS13A-1

- **Desk model**: Flexispot EK5
- **Tested with control box**: CB38M2B(IB)-1
- **Source**: Printed on the PCB of the control box.

| RJ45 pin | Name | Original Cable Color | Ethernet cable color (T568B) |
| -------- | ---------- | -------------------- | ---------------------------- |
| 8 | RESET SWIM | Brown | White-Orange |
| 7 | PIN 20 | White | Orange |
| 6 | RX | Purple | White-Green |
| 5 | TX | Red | Blue |
| 4 | GND1 | Green | White-Blue |
| 3 | +5V (VDD) | Black | Green |
| 2 | 29V+ | Blue | White-Brown |
| 1 | 29V- | Yellow | Brown |

Note that RX and TX is defined like this on receiver (control panel) side. So RX can be used to receive data, TX to send data.
| 1 | RESET SWIM | Brown | White-Orange |
| 2 | PIN 20 | White | Orange |
| 3 | RX | Purple | White-Green |
| 4 | TX | Red | Blue |
| 5 | GND1 | Green | White-Blue |
| 6 | +5V (VDD) | Black | Green |
| 7 | 29V+ | Blue | White-Brown |
| 8 | 29V- | Yellow | Brown |

Note that RX and TX is defined like this on receiver (control panel) side.
So the custom controller also uses RX to receive data and TX to send data.

#### HS01B-1

- **Desk model**: Flexispot E5B
- **Tested with control box**: CB38M2A-1
- **Source**: [nv1t/standing-desk-interceptor](https://github.com/nv1t/standing-desk-interceptor)

| RJ45 pin | Name | Original Cable Color | Ethernet cable color (T568B) |
| -------- | --------- | --------------------- | ---------------------------- |
| 8 | +5V (VDD) | Yellow | Brown |
| 7 | GND | Blue | White-Brown |
| 6 | TX | Black | Green |
| 5 | RX | Green | White-Blue |
| 4 | PIN 20 | Red | Blue |
| 3 | (unknown) | Purple | White-Green |
| 2 | SWIM | White | Orange |
| 1 | RES | Brown | White-Orange |

Note that RX and TX is defined like this on receiver (control panel) side. So RX can be used to receive data, TX to send data.

| RJ45 pin | Name |
| -------- | --------- |
| 8 | +5V (VDD) |
| 7 | GND |
| 6 | TX |
| 5 | RX |
| 4 | PIN 20 |
| 3 | (unknown) |
| 2 | SWIM |
| 1 | RES |

Note that RX and TX is defined like this on receiver (control panel) side.
So the custom controller also uses RX to receive data and TX to send data.

Other control panels / control boxes could be supported in the same way, but you would need to figure the RJ45 pinout mapping. Most control boxes have an extra RJ45 port for serial communication, but otherwise you would need to place your device in between the control panel and the control box.

### Retrieve current height

Based upon the great work of [minifloat](https://www.mikrocontroller.net/topic/493524), it became clear that the control panel utilises a [7-segment display](https://en.wikipedia.org/wiki/Seven-segment_display). Fortunately, this is very common in such devices and thus there is a lot of [documentation](https://lastminuteengineers.com/seven-segment-arduino-tutorial/) on this topic.
Based upon the great work of [minifloat](https://www.mikrocontroller.net/topic/493524), it became clear that the control panel utilises a [7-segment display](https://en.wikipedia.org/wiki/Seven-segment_display). Fortunately, this is very common in such devices and thus there is a lot of [documentation](https://lastminuteengineers.com/seven-segment-arduino-tutorial/) on this topic.

The control box sends the height as 4-bit hexadecimal, which is decoded in the control panel to drive the 7-segment display. The second number on the display also supports an optional decimal point ("8 segment").

Expand All @@ -122,6 +130,11 @@ Make sure you set the baud rate to 9600. For most LoctekMotion desks, the contro

source: [alselectro](https://alselectro.wordpress.com/2015/03/03/8051-tutorials-3-interfacing-7-segment-display/)


### Known issues
- Number entity may overshoot. For more accurate positioning, use the provided presets.


### Execute a command

The control box only accepts commands when the 'screen is active'. To activate the screen, `PIN 20` needs to be set to HIGH for about 1 second. The screen gets disabled automatically again after some amount of time receiving no commands.
Expand All @@ -146,7 +159,7 @@ All bytes combined will become the command to send to the control box. See the [
While working on this project, I found out that I am not the only one with this idea. There are a few repositories on GitHub with great research which helped me kickstart this project. ❤️

- [grssmnn / ha-flexispot-standing-desk](https://github.com/grssmnn/ha-flexispot-standing-desk) - Home Assistant integration via MQTT (micropython)
- [Dude88 / loctek_IOT_box](https://github.com/Dude88/loctek_IOT_box) - Arduino code to control via Alexa and MQTT
- [Dude88 / loctek_IOT_box](https://github.com/Dude88/loctek_IOT_box) - Arduino code to control via Alexa and MQTT
- [nv1t / standing-desk-interceptor](https://github.com/nv1t/standing-desk-interceptor) - Research on intercepting commands from Flexispot desks
- [VinzSpring / LoctekReverseengineering](https://github.com/VinzSpring/LoctekReverseengineering#assumptions) - Research and Python samples

Expand Down
File renamed without changes.
Loading