Skip to content

Commit

Permalink
Merge pull request #32 from hnez/temperature-limits
Browse files Browse the repository at this point in the history
temperatures: display over temperature notifications
  • Loading branch information
hnez committed Sep 26, 2023
2 parents 24bd697 + f9fd3c7 commit 60a84f0
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 1 deletion.
15 changes: 15 additions & 0 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,21 @@ paths:
schema:
$ref: '#/components/schemas/Measurement'

/v1/tac/temperatures/warning:
get:
summary: Get the current temperature warning state
tags: [System]
responses:
'200':
content:
application/json:
schema:
type: string
enum:
- Okay
- SocHigh
- SocCritical

/v1/tac/info/uname:
get:
summary: Get the information commonly accessed via "uname"
Expand Down
36 changes: 35 additions & 1 deletion src/temperatures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use std::time::Duration;

use async_std::sync::Arc;
use async_std::task::spawn_blocking;
use serde::{Deserialize, Serialize};

use crate::broker::{BrokerBuilder, Topic};
use crate::measurement::Measurement;
Expand Down Expand Up @@ -59,19 +60,43 @@ mod hw {
use hw::{HwMon, SysClass};

const UPDATE_INTERVAL: Duration = Duration::from_millis(500);
const TEMPERATURE_SOC_CRITICAL: f32 = 90.0;
const TEMPERATURE_SOC_HIGH: f32 = 70.0;

#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)]
pub enum Warning {
Okay,
SocHigh,
SocCritical,
}

impl Warning {
fn from_temperatures(soc: f32) -> Self {
if soc > TEMPERATURE_SOC_CRITICAL {
Self::SocCritical
} else if soc > TEMPERATURE_SOC_HIGH {
Self::SocHigh
} else {
Self::Okay
}
}
}

pub struct Temperatures {
pub soc_temperature: Arc<Topic<Measurement>>,
pub warning: Arc<Topic<Warning>>,
run: Option<Arc<AtomicBool>>,
}

impl Temperatures {
pub fn new(bb: &mut BrokerBuilder) -> Self {
let run = Arc::new(AtomicBool::new(true));
let soc_temperature = bb.topic_ro("/v1/tac/temperatures/soc", None);
let warning = bb.topic_ro("/v1/tac/temperatures/warning", None);

let run_thread = run.clone();
let soc_temperature_thread = soc_temperature.clone();
let warning_thread = warning.clone();

spawn_blocking(move || {
while run_thread.load(Ordering::Relaxed) {
Expand All @@ -82,7 +107,15 @@ impl Temperatures {
.input()
.unwrap();

let meas = Measurement::now(val as f32 / 1000.0);
let val = val as f32 / 1000.0;

// Provide a topic that only provides "is overheating"/"is okay"
// updates and not the 2Hz temperature feed.
// Subscribing to this topic is cheaper w.r.t. cpu/network use.
let warning = Warning::from_temperatures(val);
warning_thread.set_if_changed(warning);

let meas = Measurement::now(val);
soc_temperature_thread.set(meas);

sleep(UPDATE_INTERVAL);
Expand All @@ -91,6 +124,7 @@ impl Temperatures {

Self {
soc_temperature,
warning,
run: Some(run),
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/ui/screens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ mod help;
mod iobus;
mod iobus_health;
mod locator;
mod overtemperature;
mod power;
mod reboot;
mod screensaver;
Expand All @@ -46,6 +47,7 @@ use help::HelpScreen;
use iobus::IoBusScreen;
use iobus_health::IoBusHealthScreen;
use locator::LocatorScreen;
use overtemperature::OverTemperatureScreen;
use power::PowerScreen;
use reboot::RebootConfirmScreen;
use screensaver::ScreenSaverScreen;
Expand Down Expand Up @@ -84,6 +86,7 @@ pub enum AlertScreen {
UpdateInstallation,
Help,
Setup,
OverTemperature,
}

#[derive(Serialize, Deserialize, PartialEq, PartialOrd, Eq, Ord, Clone, Copy, Debug)]
Expand Down Expand Up @@ -199,6 +202,10 @@ pub(super) fn init(
Box::new(RebootConfirmScreen::new(alerts, reboot_message)),
Box::new(ScreenSaverScreen::new(buttons, alerts)),
Box::new(SetupScreen::new(alerts, &res.setup_mode.setup_mode)),
Box::new(OverTemperatureScreen::new(
alerts,
&res.temperatures.warning,
)),
Box::new(LocatorScreen::new(alerts, locator)),
]
}
114 changes: 114 additions & 0 deletions src/ui/screens/overtemperature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// This file is part of tacd, the LXA TAC system daemon
// Copyright (C) 2023 Pengutronix e.K.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

use async_std::prelude::*;
use async_std::sync::Arc;
use async_std::task::spawn;
use async_trait::async_trait;
use embedded_graphics::{
mono_font::MonoTextStyle, pixelcolor::BinaryColor, prelude::*, text::Text,
};

use super::widgets::*;
use super::{
row_anchor, ActivatableScreen, ActiveScreen, AlertList, AlertScreen, Alerter, Display,
InputEvent, Screen, Ui,
};
use crate::broker::Topic;
use crate::measurement::Measurement;
use crate::temperatures::Warning;

const SCREEN_TYPE: AlertScreen = AlertScreen::OverTemperature;

pub struct OverTemperatureScreen;

struct Active {
widgets: WidgetContainer,
}

impl OverTemperatureScreen {
pub fn new(alerts: &Arc<Topic<AlertList>>, warning: &Arc<Topic<Warning>>) -> Self {
let (mut warning_events, _) = warning.clone().subscribe_unbounded();
let alerts = alerts.clone();

spawn(async move {
while let Some(warning) = warning_events.next().await {
match warning {
Warning::Okay => alerts.deassert(SCREEN_TYPE),
Warning::SocHigh | Warning::SocCritical => alerts.assert(SCREEN_TYPE),
}
}
});

Self
}
}

impl ActivatableScreen for OverTemperatureScreen {
fn my_type(&self) -> Screen {
Screen::Alert(SCREEN_TYPE)
}

fn activate(&mut self, ui: &Ui, display: Display) -> Box<dyn ActiveScreen> {
let ui_text_style: MonoTextStyle<BinaryColor> =
MonoTextStyle::new(&UI_TEXT_FONT, BinaryColor::On);

display.with_lock(|target| {
Text::new("Temperature alert!", row_anchor(0), ui_text_style)
.draw(target)
.unwrap();

Text::new(
"TAC is overheating.\nProvide more airflow\nand check loads.",
row_anchor(2),
ui_text_style,
)
.draw(target)
.unwrap();

Text::new("SoC Temperature:", row_anchor(6), ui_text_style)
.draw(target)
.unwrap();
});

let mut widgets = WidgetContainer::new(display);

widgets.push(|display| {
DynamicWidget::text_center(
ui.res.temperatures.soc_temperature.clone(),
display,
Point::new(120, 210),
Box::new(|meas: &Measurement| format!("{:-4.0} C", meas.value)),
)
});

Box::new(Active { widgets })
}
}

#[async_trait]
impl ActiveScreen for Active {
fn my_type(&self) -> Screen {
Screen::Alert(SCREEN_TYPE)
}

async fn deactivate(mut self: Box<Self>) -> Display {
self.widgets.destroy().await
}

fn input(&mut self, _ev: InputEvent) {}
}
2 changes: 2 additions & 0 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
UpdateNotification,
ProgressNotification,
LocatorNotification,
OverTemperatureNotification,
} from "./TacComponents";

function Navigation() {
Expand Down Expand Up @@ -156,6 +157,7 @@ function Notifications() {
<>
<ConnectionNotification />
<RebootNotification />
<OverTemperatureNotification />
<ProgressNotification />
<UpdateNotification />
<LocatorNotification />
Expand Down
17 changes: 17 additions & 0 deletions web/src/TacComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -503,3 +503,20 @@ export function IOBusFaultNotification() {
</Alert>
);
}

export function OverTemperatureNotification() {
const warning = useMqttSubscription<string>("/v1/tac/temperatures/warning");

return (
<Alert
statusIconAriaLabel="Warning"
type="warning"
visible={warning !== null && warning !== "Okay"}
header="Your LXA TAC is overheating"
>
The LXA TAC's temperature is{" "}
{warning === "SocCritical" ? "critical" : "high"}. Provide better airflow
and check for overloads!
</Alert>
);
}

0 comments on commit 60a84f0

Please sign in to comment.