From 94c138d178321491b2b6210563701c9adbbe7b25 Mon Sep 17 00:00:00 2001 From: Rich Neswold Date: Fri, 23 Jan 2026 15:52:09 -0600 Subject: [PATCH 1/4] :bug: allow all weather values through It's -33 F windchill in Chicago and the dewpoint is reported as -21 F. So clipping it at 0 F doesn't seem right. We'll just let the Weather Underground data go through. It's easy enough to use a logic block to clip bad values if you're using a station that generates them (bad values.) --- drivers/drmem-drv-weather-wu/src/lib.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/drmem-drv-weather-wu/src/lib.rs b/drivers/drmem-drv-weather-wu/src/lib.rs index b761009..3641587 100644 --- a/drivers/drmem-drv-weather-wu/src/lib.rs +++ b/drivers/drmem-drv-weather-wu/src/lib.rs @@ -263,19 +263,11 @@ impl Instance { }; if let Some(dewpt) = dewpt { - if (0.0..=200.0).contains(&dewpt) { - devices.dewpt.report_update(dewpt).await - } else { - warn!("ignoring bad dew point value: {:.1}", dewpt) - } + devices.dewpt.report_update(dewpt).await } if let Some(htidx) = htidx { - if (0.0..=200.0).contains(&htidx) { - devices.htidx.report_update(htidx).await - } else { - warn!("ignoring bad heat index value: {:.1}", htidx) - } + devices.htidx.report_update(htidx).await } if let (Some(prate), Some(ptotal)) = (prate, ptotal) { From 68e274f5c608208a1b2d5747ff91616e9de07ab5 Mon Sep 17 00:00:00 2001 From: Rich Neswold Date: Fri, 23 Jan 2026 15:52:09 -0600 Subject: [PATCH 2/4] :memo: update docs for `wu` driver The new `serde`-based driver config code can support enums directly so we're sort of exposing what we use for the units. The "units" parameter now needs to be "English" or "Metric". --- drivers/drmem-drv-weather-wu/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/drmem-drv-weather-wu/README.md b/drivers/drmem-drv-weather-wu/README.md index 6acbaca..80a22e6 100644 --- a/drivers/drmem-drv-weather-wu/README.md +++ b/drivers/drmem-drv-weather-wu/README.md @@ -17,7 +17,7 @@ These are the configuration parameters for an instance of the driver. - `interval` is the number of minutes between each update. If a personal key isn't specified, the interval can't be less than 10 minutes. If this parameter isn't provided, 10 minutes is used. -- `units` can be either "metric" or "imperial" and determines how the +- `units` can be either "Metric" or "English" and determines how the device data is scaled (i.e. Celsius or Fahrenheit, etc.) ## Devices From 619905d19d0ec1d376ca67c055e73f7de1ef2dd3 Mon Sep 17 00:00:00 2001 From: Rich Neswold Date: Fri, 23 Jan 2026 15:52:09 -0600 Subject: [PATCH 3/4] :memo: fix driver API documentation --- drmem-api/src/driver/mod.rs | 54 +++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/drmem-api/src/driver/mod.rs b/drmem-api/src/driver/mod.rs index c253a23..1996735 100644 --- a/drmem-api/src/driver/mod.rs +++ b/drmem-api/src/driver/mod.rs @@ -269,6 +269,43 @@ pub trait ResettableState { /// The only function in this trait is one to register the device(s) /// with core and return the set of handles. pub trait Registrator: ResettableState + Sized + Send { + /// Before a driver is run, the set of devices it uses needs to be + /// registered. The structure that holds the registered device + /// channels should implement this trait. + /// + /// `drc` is a communication channel with which the driver makes + /// requests to the core. Its typical use is to register devices + /// with the framework, which is usually done in this method. As + /// other request types are added, they can be used while the + /// driver is running. + /// + /// `cfg` holds the configuration parameters for the instance of + /// the driver. This parameter is also passed to the driver's + /// `create_instance` method where it is more useful. Since the + /// purpose of this trait is to register devices, the other useful + /// configuration paramters would be ones that manipulate the + /// names of devices. This method should not use this parameter to + /// set up resouces (like sockets) for the driver instance. + /// + /// `override_timeout` is used to set how long a device can be + /// overridden. Some drivers control devices that can also be + /// controlled by other means than DrMem. When those devices + /// recognize they've been controlled externally, they go into + /// "override" mode in which settings are remembered but not + /// forwarded to the hardware. When override mode is entered, a + /// timer is set to expire at which the devices are again + /// controlled by DrMem . + /// + /// `max_history` is specified in the configuration file. It is a + /// hint as to the maximum number of data point to save for each + /// of the devices created by this driver. A backend can choose to + /// interpret this in its own way. For instance, the simple + /// backend can only ever save one data point. Redis will take + /// this as a hint and will choose the most efficient way to prune + /// the history. That means, if more than the limit is present, + /// redis won't prune the history to less than the limit. However + /// there may be more than the limit -- it just won't grow without + /// bound. fn register_devices<'a>( drc: &'a mut RequestChan, cfg: &'a DriverConfig, @@ -294,23 +331,6 @@ pub trait API: Send + Sync { /// validate the parameters and convert them into forms useful to /// the driver. By convention, if any errors are found in the /// configuration, this method should return `Error::BadConfig`. - /// - /// `drc` is a communication channel with which the driver makes - /// requests to the core. Its typical use is to register devices - /// with the framework, which is usually done in this method. As - /// other request types are added, they can be used while the - /// driver is running. - /// - /// `max_history` is specified in the configuration file. It is a - /// hint as to the maximum number of data point to save for each - /// of the devices created by this driver. A backend can choose to - /// interpret this in its own way. For instance, the simple - /// backend can only ever save one data point. Redis will take - /// this as a hint and will choose the most efficient way to prune - /// the history. That means, if more than the limit is present, - /// redis won't prune the history to less than the limit. However - /// there may be more than the limit -- it just won't grow without - /// bound. fn create_instance( cfg: &DriverConfig, ) -> impl Future>> + Send + '_; From fa583a9d8d63dd5adedb90df31b536050e43b248 Mon Sep 17 00:00:00 2001 From: Rich Neswold Date: Sat, 24 Jan 2026 21:44:40 -0600 Subject: [PATCH 4/4] :recycle: rename `SharedReadWriteDevice` Having "Shared" in the name was confusing, according to ChatGPT. I can see why that might be the case. So this commit renames `SharedReadWriteDevice` to `OverridableDevice`. --- drmem-api/src/driver/classes/dimmer_type.rs | 10 +++++----- drmem-api/src/driver/classes/switch_type.rs | 10 +++++----- drmem-api/src/driver/mod.rs | 10 +++++----- ...red_rw_device.rs => overridable_device.rs} | 20 +++++++++---------- 4 files changed, 25 insertions(+), 25 deletions(-) rename drmem-api/src/driver/{shared_rw_device.rs => overridable_device.rs} (98%) diff --git a/drmem-api/src/driver/classes/dimmer_type.rs b/drmem-api/src/driver/classes/dimmer_type.rs index 7a30304..0c74d6e 100644 --- a/drmem-api/src/driver/classes/dimmer_type.rs +++ b/drmem-api/src/driver/classes/dimmer_type.rs @@ -17,7 +17,7 @@ //! ``` use crate::driver::{ - ro_device::ReadOnlyDevice, shared_rw_device::SharedReadWriteDevice, + ro_device::ReadOnlyDevice, overridable_device::OverridableDevice, DriverConfig, Registrator, RequestChan, Result, }; use std::future::Future; @@ -30,10 +30,10 @@ pub struct Dimmer { pub error: ReadOnlyDevice, /// Controls the brightness setting of the dimmer. Off is 0.0 and /// full-on is 100.0. - pub brightness: SharedReadWriteDevice, + pub brightness: OverridableDevice, /// A product might include an indicator. If the hardware does, /// this device can turn it on and off. - pub indicator: SharedReadWriteDevice, + pub indicator: OverridableDevice, } impl Registrator for Dimmer { @@ -61,7 +61,7 @@ impl Registrator for Dimmer { .add_ro_device::(nm_error, None, max_history) .await?, brightness: drc - .add_shared_rw_device::( + .add_overridable_device::( nm_brightness, Some("%"), override_timeout, @@ -69,7 +69,7 @@ impl Registrator for Dimmer { ) .await?, indicator: drc - .add_shared_rw_device::( + .add_overridable_device::( nm_indicator, None, override_timeout, diff --git a/drmem-api/src/driver/classes/switch_type.rs b/drmem-api/src/driver/classes/switch_type.rs index 1921109..b7f9334 100644 --- a/drmem-api/src/driver/classes/switch_type.rs +++ b/drmem-api/src/driver/classes/switch_type.rs @@ -17,7 +17,7 @@ //! ``` use crate::driver::{ - ro_device::ReadOnlyDevice, shared_rw_device::SharedReadWriteDevice, + ro_device::ReadOnlyDevice, overridable_device::OverridableDevice, DriverConfig, Registrator, RequestChan, Result, }; use std::future::Future; @@ -30,10 +30,10 @@ pub struct Switch { pub error: ReadOnlyDevice, /// Indicates the state of the switch. Writing `true` or `false` /// turns the switch on and off, respectively. - pub state: SharedReadWriteDevice, + pub state: OverridableDevice, /// A product might include an indicator. If the hardware does, /// this device can turn it on and off. - pub indicator: SharedReadWriteDevice, + pub indicator: OverridableDevice, } impl Registrator for Switch { @@ -57,7 +57,7 @@ impl Registrator for Switch { .add_ro_device::(nm_error, None, max_history) .await?, state: drc - .add_shared_rw_device::( + .add_overridable_device::( nm_state, None, override_timeout, @@ -65,7 +65,7 @@ impl Registrator for Switch { ) .await?, indicator: drc - .add_shared_rw_device::( + .add_overridable_device::( nm_indicator, None, override_timeout, diff --git a/drmem-api/src/driver/mod.rs b/drmem-api/src/driver/mod.rs index 1996735..0f769b7 100644 --- a/drmem-api/src/driver/mod.rs +++ b/drmem-api/src/driver/mod.rs @@ -25,14 +25,14 @@ pub type DriverConfig = value::Table; pub mod classes; mod ro_device; mod rw_device; -mod shared_rw_device; +mod overridable_device; pub use ro_device::{ReadOnlyDevice, ReportReading}; pub use rw_device::{ ReadWriteDevice, RxDeviceSetting, SettingReply, SettingRequest, TxDeviceSetting, }; -pub use shared_rw_device::SharedReadWriteDevice; +pub use overridable_device::OverridableDevice; /// Defines the requests that can be sent to core. Drivers don't use /// this type directly. They are indirectly used by `RequestChan`. @@ -219,13 +219,13 @@ impl RequestChan { /// `InternalError`, then the core has exited and the /// `RequestChan` has been closed. Since the driver can't report /// any more updates or accept new settings, it may as well shutdown. - pub async fn add_shared_rw_device( + pub async fn add_overridable_device( &self, name: device::Base, units: Option<&str>, override_duration: Option, max_history: Option, - ) -> Result> { + ) -> Result> { let (tx, rx) = oneshot::channel(); let result = self .req_chan @@ -241,7 +241,7 @@ impl RequestChan { if result.is_ok() { if let Ok(v) = rx.await { return v.map(|(rr, rs, prev)| { - SharedReadWriteDevice::new( + OverridableDevice::new( rr, rs, prev.and_then(|v| T::try_from(v).ok()), diff --git a/drmem-api/src/driver/shared_rw_device.rs b/drmem-api/src/driver/overridable_device.rs similarity index 98% rename from drmem-api/src/driver/shared_rw_device.rs rename to drmem-api/src/driver/overridable_device.rs index 4577bc8..b82236c 100644 --- a/drmem-api/src/driver/shared_rw_device.rs +++ b/drmem-api/src/driver/overridable_device.rs @@ -5,7 +5,7 @@ /// users outside of DrMem. LED WiFi light bulbs are one, obvious /// example. For devices that can be controlled outside of DrMem, we /// need a way to cooperatively control them. That's what -/// `SharedReadWriteDevice`s do. +/// `OverridableDevice`s do. /// /// A driver that uses this type of device must do these steps in /// their main loop: @@ -16,8 +16,8 @@ /// - after setting the hardware to a new value, a poll should /// immediately be done followed by a `.report_update()` /// -/// `SharedReadWriteDevice`s implement a simple state machine to know -/// how to handle incoming incoming settings. +/// `OverridableDevice`s implement a simple state machine to know how +/// to handle incoming incoming settings. use crate::{ device, driver::{rw_device, ReportReading, RxDeviceSetting, SettingReply}, @@ -62,14 +62,14 @@ enum State { }, } -pub struct SharedReadWriteDevice { +pub struct OverridableDevice { state: State, override_duration: Option, report_chan: ReportReading, set_stream: rw_device::SettingStream, } -impl SharedReadWriteDevice +impl OverridableDevice where T: device::ReadWriteCompat, { @@ -79,7 +79,7 @@ where desired_value: Option, override_duration: Option, ) -> Self { - SharedReadWriteDevice { + OverridableDevice { state: desired_value .map(|value| State::SettingTrans { value: (value, None), @@ -453,7 +453,7 @@ where } } -impl super::ResettableState for SharedReadWriteDevice +impl super::ResettableState for OverridableDevice where T: device::ReadWriteCompat, { @@ -476,7 +476,7 @@ mod tests { time::{timeout, Duration}, }; - // Helper function that creates a `SharedReadWriteDevice`. + // Helper function that creates a `OverridableDevice`. fn mk_device( init: Option, @@ -484,7 +484,7 @@ mod tests { ) -> ( TxDeviceSetting, mpsc::Receiver, - SharedReadWriteDevice, + OverridableDevice, ) { let (rrtx, rrrx) = mpsc::channel(20); let (srtx, srrx) = mpsc::channel(20); @@ -492,7 +492,7 @@ mod tests { ( srtx, rrrx, - SharedReadWriteDevice::new( + OverridableDevice::new( Box::new(move |v| { let rrtx = rrtx.clone();