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

Support for OMOTE Hub #100

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open

Support for OMOTE Hub #100

wants to merge 21 commits into from

Conversation

Stuckya
Copy link
Contributor

@Stuckya Stuckya commented Mar 11, 2025

OMOTE Hub

The goal of this PR is to send commands to a hub instead of sending IR commands directly from the remote.

The hub consumes messages and is responsible for communicating with the devices.
Currently, the OMOTE hub is written in Python and can be run on any linux machine (in my case a Raspberry Pi 4).

Hub transports

Communication between the remote and the hub follows a pub/sub pattern. This allows us to easily swap transports on both the remote and the hub depending on user preference, hardware availability, and use-case.

  • ESP-NOW
    • Pros
      • faster boot times (~450ms faster wake compared to MQTT over Wi-Fi)
      • long range (up-to 185 meters line-of-sight, compared to 80 meters Wi-Fi and only 15 meters BLE)
      • low latency (135% faster than Wi-Fi and 350% faster than BLE when transferring a payload of 50 bytes)
      • simple, no extra infrastructure required
    • Cons
      • max payload size of 250 bytes
      • power consumption appears to be about the same as Wi-Fi
  • MQTT over Wi-Fi
    • Pros
      • very flexible
      • virtually no limit on payload size
    • Cons
      • slower boot time
      • higher latency compared to ESP-NOW
      • shorter range
      • MQTT requires an additional layer of infrastructure / maintenance / complexity
      • MQTT may drop messages unless QOS is changed

Contract between hub and remote

The remote emits RemoteEvent's, the hub subscribes to these events. The data contract is simple yet expressive (remember we have a 250 byte payload cap if using ESP-NOW).

{
  "device": "APPLE_TV",
  "command": "UP",
  "type": "SHORT",
  "data": [] // optional additional data
}

Currently the hub doesn't communicate 2-way, though this is something I'd like to enable soon. For example, I'd love to display the audio level from an AVR or "What's Playing" information on the remote.
The hub will likely emit something like HubFeedbackEvent's.

{
  "device": "APPLE_TV",
  "data": ?
}

The Hub

The hub primarily supports RS-232 and IP Control (HTTP) transports for different devices. I'd like to explore IR emitters and Bluetooth in the near future. I've found controlling IR emitters from Python to be challenging in my tests thus far and might need help.

I'll be opening a separate PR shortly which adds a new directory containing the hub software with more details on functionality.

// Show the message in the UI
showEspNowMessage(jsonStr);

// TODO: Process the command based on device and command
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is more of a stub for 2-way communication with the hub

Comment on lines +138 to +142
struct CommandExecutionParams {
uint16_t commandId;
CommandExecutionType commandType = CMD_SHORT;
std::string additionalPayload = "";
};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me know what you think of CommandExecutionParams. I've really been enjoying structs in my cpp programming.

This was largely driven by wanted to have the commandType so the hub can send different commands based on the key press type.

Comment on lines +22 to +28
inline void execute_hub_command(uint16_t command, CommandExecutionType type = CMD_SHORT, const std::string& additionalPayload = "") {
CommandExecutionParams params;
params.commandId = command;
params.commandType = type;
params.additionalPayload = additionalPayload;
executeCommand(params);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This will allow us to send hub commands from scenes, like scene_allOff.cpp. Ex:

#if (ENABLE_HUB_COMMUNICATION == 1)
  execute_hub_command(LGTV_POWER_OFF);
  execute_hub_command(APPLETV_POWER_OFF);
  execute_hub_command(SONYAVR_POWER_OFF);
#else
  executeCommand(SAMSUNG_POWER_ON);
  delay(500);
  ...
#endif

@KlausMu
Copy link
Collaborator

KlausMu commented Mar 13, 2025

Thanks @Stuckya for this PR.
I already started review and added some comments. More comments will follow the next days. Adding more comments does not mean I don't appreciate this PR. It simply means I need more than one day for reviewing.

Some more thoughts:

  • could you please already start thinking about on how to integrate this into the wiki. Probably should be somewhere here Could you provide some markup for the wiki? Unfortunately cannot be provided as PR
  • code for the hub itself should maybe provided in a completely separate repo, since the underlying technology is probably completely different. What do you think? I have seen this concept in other projects, where e.g. there were separate repos for the backend server, the web frontend, the Android app, ...

@Stuckya
Copy link
Contributor Author

Stuckya commented Mar 14, 2025

  • could you please already start thinking about on how to integrate this into the wiki. Probably should be somewhere here Could you provide some markup for the wiki? Unfortunately cannot be provided as PR

Yes, I have some rough notes but need to sit down and spend time on documentation. Should I share the markdown over Discord?

  • code for the hub itself should maybe provided in a completely separate repo, since the underlying technology is probably completely different. What do you think?

I don't have a super strong opinion here and we might want to consult @CoretechR too.
I've worked professionally in some large monorepos with multiple languages without problem. I could easily see the hub becoming another top-level directory. Example:

OMOTE/
├── CAD/
├── PCB/
├── remote/
├── hub/
└── images/

I like the monorepo approach because it is easier for the user. They don't have to worry about cloning multiple repos to get started.

That said, I do think multiple repos can work well if there is a Github "Organization". This also helps with managing access for multiple core-contributors.

Which would look something more like:

https://github.com/OMOTE/omote-remote
https://github.com/OMOTE/omote-hub

@KlausMu
Copy link
Collaborator

KlausMu commented Mar 14, 2025

Yes, I have some rough notes but need to sit down and spend time on documentation. Should I share the markdown over Discord?

What about sharing it here? Everything at one single place.

I don't have a super strong opinion here and we might want to consult @CoretechR too. I've worked professionally in some large monorepos with multiple languages without problem.

The only concern I have that you will use completely different technologies for the different directories. For a professional, it is no problem having Java, Angular, docker-compose and whatever all in the same repo. But here, some people already struggle using only PlatformIO for compiling and uploading the firmware to the ESP32.

I haven't seen the hub code until now and how it works, maybe we can discuss this later.
I also wouldn't merge this PR before we also integrated or linked in some way the hub.

That said, I do think multiple repos can work well if there is a Github "Organization". This also helps with managing access for multiple core-contributors.

That looks interesting. @CoretechR ?

@CoretechR
Copy link
Owner

@KlausMu I have not looked into it in detail, but a GitHub organization seems like a good fit for open source projects like this. We could also split the project into hardware and software repos. But all of that should be thought through well.

@@ -21,40 +21,55 @@ extern "C"
#define OMOTE_LOG_LEVEL CONFIG_OMOTE_LOG_DEFAULT_LEVEL
#endif

// Include the Arduino layer for all platforms
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is the change in file omote_log.h good for?
First I thought changing from Serial.printf to printf for linux would solve the problem with the delayed log messages when running the application with the upload button. But it didn't solve it.

@@ -21,40 +21,55 @@ extern "C"
#define OMOTE_LOG_LEVEL CONFIG_OMOTE_LOG_DEFAULT_LEVEL
#endif

// Include the Arduino layer for all platforms
Copy link
Collaborator

Choose a reason for hiding this comment

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

How is the change of this file related to the original PR "Support for OMOTE Hub"?
I would like to keep changes separate, to finish each one as soon as possible.
Currently I am afraid that closing the PR "Support for OMOTE Hub" still needs some time, so other changes should be in separate PRs.

@KlausMu
Copy link
Collaborator

KlausMu commented Mar 23, 2025

Did you see that the PR still does not compile?

Compiling .pio/build/esp32-s3-Rev5andHigher/src/applicationInternal/keys.cpp.o
In file included from src/applicationInternal/hardware/arduinoLayer.h:7,
                 from src/applicationInternal/omote_log.h:26,
                 from src/applicationInternal/hub/hubManager.cpp:3:
/home/klaus/.platformio/packages/framework-arduinoespressif32/cores/esp32/Arduino.h:155:6: error: conflicting declaration of C function 'long int random(long int)'
 long random(long);
      ^~~~~~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants