Skip to content

Serial Bus No. 4: Add subscribing to properties over serial bus#193

Open
JensOgorek wants to merge 17 commits intomainfrom
serial_bus_subscribe_simple
Open

Serial Bus No. 4: Add subscribing to properties over serial bus#193
JensOgorek wants to merge 17 commits intomainfrom
serial_bus_subscribe_simple

Conversation

@JensOgorek
Copy link
Copy Markdown
Contributor

@JensOgorek JensOgorek commented Feb 25, 2026

Motivation

Allow multiple ESP32s on a serial bus to share property values across nodes. The coordinator can subscribe to a property on a peer node and receive live updates every step. Handles restart recovery in both directions.

Implementation

A subscribe(node, "module.prop", default) method is added to SerialBus. Internally, a single Subscription struct is used on both sides of the bus: property == nullptr means coordinator-side (what to watch remotely), non-null means peer-side (who to push updates to).

Proxy: When subscribe() is called through an Expander, the Proxy pre-creates the subscription property with its default value locally. This ensures the property is available immediately for rules, without waiting for the first update from the Expander.

Protocol:

  • __SUB__module.prop:local_name — coordinator asks peer to start sending updates
  • __UPD__local_name=value — peer sends current value each step; coordinator prepends its own module name before calling process_line
  • __UNSUB__ — coordinator tells peer to clear all its subscriptions

Restart recovery:

  • Peer restarts: coordinator detects poll timeout and flags the peer. Once the peer responds again, the coordinator re-sends all __SUB__ commands for that node.
  • Coordinator restarts: peer sends updates the coordinator doesn't recognize — coordinator warns, sends __UNSUB__, and stale subscriptions are dropped cleanly. The coordinator's startup script re-establishes the subscriptions it needs.

Test setup

The following is the setup I used to develop this.

Core ESP setup

# Serial and Expander on Core ESP
serial = Serial(26, 27, 115200, 1)
p0 = Expander(serial)

# Serial on Expander p0
p0_serial = p0.Serial(26, 27, 115200, 1)

# Bus on Expander p0 with ID 2
bus = p0.SerialBus(p0_serial, 2)
# Make "bus" the coordinator and add the one other peer with ID 1
bus.make_coordinator(1)

# create a subscription for "test.level" with the default "0"
bus.subscribe(1, "test.level", 0)
# this creates bus.test_level_1 as a propery on the bus module

Peer1 ESP setup

# Create Bus on Peer 1
serial = Serial(26, 27, 115200, 1)
bus = SerialBus(serial, 1)

# Add a Test input to subscribe to
test = Input(32)

Discussable

I also created the branch Dotted Properties. It contains changes to the Lizard OWL language to handle property names with dots. So property names don't have to be changed for that, for example: bus.test.level_1 as a subscription from test.level on peer 1.
Since this change is a bit more extreme, I moved it to a different branch, so we can talk about that if we want that here.

Future changes/updates

A possible change that would make this more intuitive is to use the variables that the Lizard firmware provides.
Since we usually add the Serial Bus to an Expander, this would mean we have to find a simple way to synchronize the variables from the Expander to the Core ESP. There is currently no simple way besides using the properties as a vessel, but then it would just be a remapping from property to variable.

Example core ESP setup

# Serial and Expander on Core ESP
serial = Serial(26, 27, 115200, 1)
p0 = Expander(serial)

# Serial on Expander p0
p0_serial = p0.Serial(26, 27, 115200, 1)

# Bus on Expander p0 with ID 2
bus = p0.SerialBus(p0_serial, 2)
# Make "bus" the coordinator and add the one other peer with ID 1
bus.make_coordinator(1)

# create a subscription for "test.level" using the "test_level_local_name" variable
int test_level_local_name = 0
bus.subscribe(1, "test.level", "test_level_local_name")
# this would now update test.level's value onto the variable "test_level_local_name"

Progress

  • The implementation is complete.
  • Tested on hardware (or is not necessary).
  • Documentation has been updated (or is not necessary).
  • Add examples

@JensOgorek JensOgorek added the enhancement New feature or request label Mar 9, 2026
@JensOgorek JensOgorek added this to the 0.11.0 milestone Mar 9, 2026
@JensOgorek JensOgorek self-assigned this Mar 9, 2026
@JensOgorek JensOgorek marked this pull request as ready for review March 9, 2026 16:03
Copy link
Copy Markdown
Collaborator

@falkoschindler falkoschindler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before reviewing this PR, I think it's better to

  1. merge PR #189 into main,
  2. merge main into this branch,
  3. resolve all conflicts, and
  4. check if configuring and subscribing to properties still works.

Since all "Serial Bus" branches affect the same area of the repository, it feels sketchy to review No. 4 without the final version of No. 3.

@JensOgorek
Copy link
Copy Markdown
Contributor Author

JensOgorek commented Mar 14, 2026

I merged 3 into main, main into 4 and tested configure and subscribe. All works fine.

@falkoschindler
Copy link
Copy Markdown
Collaborator

We agreed to postpone this PR for now until our use case is clearer. We might not need to support a serial bus on an expander, which would simplify things and open possibilities for accessing properties.

Just a few random thoughts after briefly reading the code (can be addressed later):

  • The resulting API bus.test_level_1 is weird. We already discussed alternatives, but haven't found a really good solution yet.
  • && arguments.size() >= 3 silently ignores invalid argument list, doesn't check argument types.
  • We should wrap single-line blocks in {} (for consistence).
  • We could think about renaming __SUB__ to __SUBSCRIBE__ because why not.
  • Why unsubscribe on exception?

@falkoschindler falkoschindler modified the milestones: 0.11.0, 0.X.0 Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants