Non-Linux Dev Envs#194
Non-Linux Dev Envs#194DXCanas wants to merge 10 commits intoJaapvanEkris:0.9.7-(under-construction)from
Conversation
…y with graceful fallbacks Changed BleManager to lazy-load native modules only on Linux platform and throw descriptive error on unsupported platforms. Updated PeripheralManager error handling to downgrade BLE initialization errors from error to warn level and automatically disable BLE/HRM modes when unavailable. Made GPIO timer service conditional on Linux platform in server.js with warning message for other platforms.
There was a problem hiding this comment.
Thanks, actually this is a good idea, and it would remove a lot of pain from me too. But I would also add a config option that disables these in case of linux.
Reason is:
- I sometimes do simulate on windows (i comment out everything that does not exist on and run things bare bones). you solution works for this
- I sometimes develop on a headless linux server (not the pi) which is linux but does not have Bluetooth (well it does but its off obviously) and does not have GPIO
What do you think?
Abasz
left a comment
There was a problem hiding this comment.
Just some general ideas on the code
|
If it helps people, let's do this. Some practical points:
|
Introduces the `simulateWithoutHardware` flag to the default configuration and config validation. This enables developers to bypass GPIO and BLE hardware checks to simulate the environment on headless servers or non-Linux systems without causing error logs. AI-assisted-by: Gemini 3.1 Pro
Removes the static `process.platform === 'linux'` check in favor of dynamically importing `hci-socket` and `ble-host`. Uses the new `simulateWithoutHardware` config flag to bypass BLE initialization when requested. Refactors `open()` to use guard clauses, preventing deep nesting and improving readability. Catches and logs missing dependencies cleanly. AI-assisted-by: Gemini 3.1 Pro
Removes the static `process.platform === 'linux'` check from `server.js` and moves hardware checking into `GpioTimerService.js`. Uses dynamic imports for `pigpio` wrapped in a try/catch block. If `simulateWithoutHardware` is true or if `pigpio` fails to load (e.g., on non-Raspberry Pi devices or without root), the service logs a warning and exits cleanly instead of crashing the app. AI-assisted-by: Gemini 3.1 Pro
DXCanas
left a comment
There was a problem hiding this comment.
Isolate this stuff well and log what conclusion is drawn (so start the modules with the if...then...else statement which always logs), to make sure that we can detect problems from logging
Tried to make sure the logs robust enough @JaapvanEkris
Tested; server start on non-compatible platform is still a little noisy because we log the errors, but everything spins up fine.
app/gpio/GpioTimerService.js
Outdated
| let pigpio | ||
| try { | ||
| const pigpioModule = await import('pigpio') | ||
| pigpio = pigpioModule.default | ||
| } catch (error) { | ||
| log.warn('Failed to load pigpio module. GPIO service will be unavailable (Linux/Raspberry Pi only).', error.message) | ||
| return | ||
| } | ||
|
|
There was a problem hiding this comment.
Is this robust enough without having to look for specific Pi model names @JaapvanEkris ?
There was a problem hiding this comment.
No, it's not. Digging some more.
There was a problem hiding this comment.
I ended up going with a caught error and message:
The failure message is annoying, but the JS layer seems to obfuscate any compatability checks at the C-library level.
So this is what we get:
Server: peripheral requested refreshPeripheralConfig
webserver running on port 80
+-----------------------------------------------------------------------+
| Warning: The pigpio C library can't be loaded on this machine and any |
| attempt to use it will fail. |
| |
| Error: "Module did not self-register" |
| ------------------------------------ |
| If you are working on a Raspberry Pi and see a "Module did not self- |
| register" error, this typically indicates that the installation |
| instructions were not exactly followed. For further details see the |
| installation section of the readme at |
| https://github.com/fivdi/pigpio#installation |
| Note that step 1 of the installation instructions must be completed |
| before step 2. |
+-----------------------------------------------------------------------+
Invoking require('bindings')('pigpio.node') resulted in the follwoing error:
Error: Module did not self-register: '/Users/david/Projects/openrowingmonitor/node_modules/pigpio/build/Release/pigpio.node'.
at Module._extensions..node (node:internal/modules/cjs/loader:1920:18)
at Module.load (node:internal/modules/cjs/loader:1481:32)
at Module._load (node:internal/modules/cjs/loader:1300:12)
at TracingChannel.traceSync (node:diagnostics_channel:328:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:245:24)
at Module.require (node:internal/modules/cjs/loader:1504:12)
at require (node:internal/modules/helpers:152:16)
at bindings (/Users/david/Projects/openrowingmonitor/node_modules/bindings/bindings.js:112:48)
at /Users/david/Projects/openrowingmonitor/node_modules/pigpio/pigpio.js:8:31
at Object.<anonymous> (/Users/david/Projects/openrowingmonitor/node_modules/pigpio/pigpio.js:43:3)
-------------------------------------------------------------------------------
Hardware initialization: pigpio C library failed to initialize (likely not a supported Raspberry Pi or missing root). GPIO service is bypassed.
Which. I mean. Not great, but it works, and if someone's using not root they still get the scary messages.
I did explicitly check for the devices mentioned, but thought it was a bit brittle?
893a01e
Updates `GpioTimerService` to explicitly read `/proc/device-tree/model` to confirm it is running on a supported Raspberry Pi (3, 4, or Zero 2W) before attempting to load `pigpio`. Updates `BleManager` to explicitly check for Linux before attempting to load `hci-socket`. Both services now log explicit messages detailing their initialization decisions as requested by maintainers, ensuring clear visibility into why hardware modules are bypassed or loaded. AI-assisted-by: Gemini 3.1 Pro
cfca9fe to
e87451b
Compare
…on failure gracefully The `pigpio` JS wrapper exports functions even if the underlying C library fails to initialize (e.g. on macOS or non-Pi Linux without root), causing a hard crash later when those undefined C-bindings are called. This commit explicitly wraps the first call to `pigpio.hardwareRevision()` in a try/catch block to catch the `TypeError: is not a function`. This prevents the application from crashing and instead cleanly bypasses the GPIO service as requested by maintainers. AI-assisted-by: Gemini 3.1 Pro
e87451b to
fcabffd
Compare
Abasz
left a comment
There was a problem hiding this comment.
Just some general ideas on the code
… JSDoc imports Replaces the temporary `any` types with `typeof import(...)` for the BLE modules (`hci-socket` and `ble-host`). This restores strong type checking for the class properties while keeping the actual module loading deferred to runtime, satisfying the requirement to lazy-load these modules only on supported platforms (Linux) without losing static analysis benefits.
This reverts commit 5a352e5.
Hey guys. Last one for tonight, promise.
So. My current laptop is a mac, though I manage linux servers for work. Go figure.
But I have been replaying raw data to test GUI updates. And the server will not start without linux env checks.
This is Claude's attempt at catching those errors, so that I can work on the project. I am tired of merging and un-merging this into candidate branches :)