Ideal Reality

興味の赴くままに
  1. トップ
  2. 投稿
  3. FlexiSpot E7 Proのコントローラーの信号を解析してみた
add_22026年2月1日 18時22分
refresh2026年2月5日 6時55分

FlexiSpot E7 Proのコントローラーの信号を解析してみた

FlexiSpotの電動昇降式デスクにESP32を接続して、WebブラウザやHome Assistant等から操作できるようにするというのは、まあまあメジャーな改造かと思います。

GitHub - iMicknl/LoctekMotion_IoT

Learn how to connect your Flexispot (LoctekMotion) desk to the internet. This repository contains a collection of scripts to get your started, combined with research and instructions.

コントローラーとの通信についてはこちらのGitHubレポジトリにまとまってるし、HomeAssistantと連携させるためのESPHomeのyamlファイルも配布されているため、簡単に導入することができます。
とはいえ、こちらはあくまで純正コントローラーを残しつつESP32を追加する改造であるため、純正コントローラーを置き換えできる代物ではありません。
今回、自分はFlexiSpotのコントローラーを外して、M5Stack Tab5を設置する計画なので、なるべく純正コントローラーと同等の使い勝手を実現できるように通信仕様を調査してみました。

スポンサーリンク

マイコン・接続

制御するマイコンにはESP32S3(AtomS3-Lite)を使いました。接続は参考元のGitHubレポジトリとそんなに相違ありません。マイコンが違うからGPIOピンが違うくらい

RJ45 PinFlexiSpotAtom-S3 Lite
8+5V (VDD)5V (VIN_5V)
7GNDG (GND)
6RXG5 (UART1 TX)
5TXG6 (UART1 RX)
4DetectG7 (GPIO7)
3
2
1

Pin8と7は電源
Pin6と5を使ってUARTで通信します。Pin6がESP32->FlexiSpot方向の通信で、Pin5がFlexiSpot->ESP32の通信になります。
Pin4について、参考元のGitHubではPIN 20と記載されており、その他調べるとWake Upピンと説明されていることがあったりしますが、自分が手元で試した感じだと

  • Highにしている間FlexiSpot本体からUARTのパケットが届く
  • LowにするとFlexiSpotからの通信が止まる
  • コントローラーは常時5Vを出力
  • Low -> HighになったタイミングでLCD出力

という感じでコントローラーが接続されているかどうかを検出するために使っていそうな挙動だったので、Detectって表記にしました。
なので、ここはESP32と接続する必要はなく、Pin8とショートさせるだけでいいのですが、Low->Highと切り替えることで任意のタイミングでLCDを点灯させることができるため繋いでおいても損はないと思います。

なお、FlexiSpotが電源Offの場合にPin4を1秒間Highにして電源Onにする必要があるとの記述も見かけましたが、とくにその必要はなさそうでした。
Pin4がHighなら通信可能 == Pin4は常時Highにしておけばいい、それだけです。

パケット

通信は9600bpsのUART上で、パケット単位でやり取りされます。

構造

UART上での通信に使ってるパケット構造です。0x9Bから始まり、0x9Dで終わります。
その他特殊なエンコードとかはありません。

SizeNote
0x9B1開始バイト
Length1パケットの長さ。Type,Payload,Checksum,0x9Dのサイズ合計値
Type1データタイプ
Payload0~N実際にやり取りするデータ
Checksum2Length,Type,Payload(上図の青い範囲)のCRC-16/MODBUS, Big Endian
0x9D1終了バイト

主なパケット

状態リクエスト

DirectionLengthTypePayload
本体 -> コントローラー40x11なし

本体からコントローラーに対する状態取得リクエストです。Payloadはありません。
約40ms間隔で本体からコントローラーに送られ、コントローラーはこのパケットを受信すると次セクションで説明するボタンの状態を本体に応答します。

ボタンの状態

DirectionLengthTypePayload
コントローラー -> 本体60x02ボタンの押下状態(2バイト)

参考元ではCommandと表現されていますが、これはコントローラーからFlexiSpotを操作するコマンドとかではなく、単に押されているボタンの状態を表現しています。
HID KeyboardのInput Reportみたいなものです。
なので、Payloadが 00 00 のパケットは、Wake Upコマンドではなく、単にボタンが押されていないという状態を送っているだけですね。

ボタンPayload Bit
Up01 00
Down02 00
M20 00
Preset 104 00
Preset 208 00
Preset 3 (stand)10 00
Preset 4 (sit)00 01

本体側から 9b 04 11 7c c3 9d が届いたときに、ボタンが何も押されていなければ 9b 06 02 00 00 6c a1 9d を、Upが押されていれば 9b 06 02 01 00 fc a0 9d を送るようなシーケンスになります。
また、Up/Downボタン同時押しで緊急停止の感度調整ができたりしますが、そういうボタンの同時押しがされているときは、たとえばUpとDown両方同時押しなら 01 0002 00 の OR をとった 03 00 をPayloadに入れて 9b 06 02 03 00 9c a1 9d を送る形になります。

画面表示の状態

DirectionLengthTypePayload
本体 -> コントローラー70x127セグメントLEDの表示状態(3バイト)

これに関しては参考元のGitHubレポジトリ記載の通りです。
7セグメントLEDのどの場所を点灯させるか指定する形で表示内容が届きます。Payloadは3桁の表示内容で3バイトで、画面が消えているときはもちろん 00 00 00 が来ます。
これを読み取ってうまく文字列・数値に変換することで高さを取得することができます。
また、数字以外にもたとえばMボタンを押したときに 5- と表示されるハイフンだったり、ロック時の LoC とかリセット時の RST なんかが表示されるため、以下の表くらいの表示は対応しておくといいかと思います。
ちなみに、RSTのSは5と区別がつかないので、そこはうまくR5Tが来たときに置き換えるとかで対処する必要があります。

Payloadの値表示Payloadの値表示Payloadの値表示
0x3F00xBF0.0x40-
0x0610x861.0x39C
0x5B20xDB2.0x79E
0x4F30xCF3.0x38L
0x6640xE64.0x77R
0x6D50xED5.0x31T
0x7D60xFD6.0x5Co
0x0770x877.
0x7F80xFF8.
0x6F90xEF9.

不明なパケット1

DirectionLengthTypePayload
本体 -> コントローラー40x15なし

本体からコントローラーに対して頻繁に送られているパケットです。
約16msごとに本体から届いていて、状態リクエストよりも頻度が高いです。
Keep-aliveとか、コントローラーのクロックとかで使う用なのかなと推測してて、コントローラーを自作するときは特に読み取る必要なさそうだなと思っています。

不明なパケット2

DirectionLengthTypePayload
コントローラー -> 本体50x020x82

コントローラーが電源On直後、最初の状態リクエストが届くまで100ms間隔で本体に送っています。
おそらくこれがコントローラー側から本体を叩き起こすWake Upコマンドに相当するものじゃないかなと思っているのですが、それがなくてもE7 Proは動いてくれるので、これも特に必要はなさそうです。

スポンサーリンク

ロック

Mボタン長押しでロックする際に、青色のLEDが点滅・点灯したり音が鳴ります。
これに関してはFlexiSpot本体側ではなくコントローラー側で制御してそうな感じがしました。解析結果としては以下のような感じ。

  • LED点灯(ロック)・消灯(ロック解除)時で画面表示以外のパケットに変化がない
  • 純正コントローラーとESP32両方接続して、ESP32側からMボタン長押し操作をしてもLED点滅・ブザー鳴動しない
  • コントローラーから電源とTx/Rx以外の接続を遮断してもLED・ブザーが動作する

なので、ロック時の挙動を再現するなら

  • Mボタンが押されている && LED表示がLoC: LED点滅 + ブザー
  • 現在or最後のLED表示内容がLoC: LED点灯
  • それ以外: LED消灯

のような形でいいかなと思います。

実装

UARTで通信するだけですが、Pattern detectionを使って、0x9dが来たタイミングで処理できるようにしておくと、UARTでパケットを受信してから実際に処理するまでの遅延を小さくできるのでいいでしょう。
以下にIDF Componentとして使える形で公開しているので参考にどうぞ。

idf-components/flexispot at main · Hiroki-Kawakami/idf-components

Reusable ESP-IDF Components. Contribute to Hiroki-Kawakami/idf-components development by creating an account on GitHub.

ESP-IDF環境なら、idf_component.ymlに以下のように記述するとそのまま使えます。

dependencies:
  flexispot:
    git: https://github.com/Hiroki-Kawakami/idf-components.git
    path: flexispot
    version: main
スポンサーリンク

余談

今回僕の目的としてはM5Stack Tab5から操作することなので、とりあえずAtomS3-LiteをGATT ServerにしてBluetooth経由で操作しました。
FlexiSpot用のサービスにボタン用のWrite可能なCharacteristicと、ディスプレイ表示用のRead+Notify可能なCharacteristicを用意する形です。

共有

この記事が役に立ったならば、シェアしていただけると嬉しいです。

スポンサーリンク
関連する投稿
関連する投稿はありません
プロフィール
Hiroki Kawakami

サイトを作り替えています

スポンサーリンク