Add enhanced fan logic
This commit is contained in:
@@ -137,7 +137,6 @@ TOWERD_RENOGY_TIMEOUT_MS=1000
|
|||||||
```
|
```
|
||||||
|
|
||||||
Thank you to [ESP32ArduinoRenogy](https://github.com/wrybread/ESP32ArduinoRenogy) for doing all the hard work!
|
Thank you to [ESP32ArduinoRenogy](https://github.com/wrybread/ESP32ArduinoRenogy) for doing all the hard work!
|
||||||
|
|
||||||
## systemd
|
## systemd
|
||||||
|
|
||||||
`towerd` loads `/etc/towerd/env` via `EnvironmentFile`. If using Docker for InfluxDB, ensure Docker starts before towerd:
|
`towerd` loads `/etc/towerd/env` via `EnvironmentFile`. If using Docker for InfluxDB, ensure Docker starts before towerd:
|
||||||
@@ -149,3 +148,4 @@ Wants=docker.service
|
|||||||
```
|
```
|
||||||
|
|
||||||
Add those lines to `/etc/systemd/system/towerd.service` under `[Unit]`.
|
Add those lines to `/etc/systemd/system/towerd.service` under `[Unit]`.
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
services:
|
|
||||||
influxdb:
|
|
||||||
image: influxdb:2.7
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "127.0.0.1:8086:8086"
|
|
||||||
volumes:
|
|
||||||
- influx-data:/var/lib/influxdb2
|
|
||||||
environment:
|
|
||||||
DOCKER_INFLUXDB_INIT_MODE: setup
|
|
||||||
DOCKER_INFLUXDB_INIT_USERNAME: admin
|
|
||||||
DOCKER_INFLUXDB_INIT_PASSWORD: ${INFLUXDB_INIT_PASSWORD}
|
|
||||||
DOCKER_INFLUXDB_INIT_ORG: ${INFLUXDB_INIT_ORG:-tower}
|
|
||||||
DOCKER_INFLUXDB_INIT_BUCKET: ${INFLUXDB_INIT_BUCKET:-tower}
|
|
||||||
DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: ${INFLUXDB_INIT_ADMIN_TOKEN}
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
influx-data:
|
|
||||||
@@ -34,8 +34,8 @@ impl Default for Config {
|
|||||||
Self {
|
Self {
|
||||||
status_pin: 4,
|
status_pin: 4,
|
||||||
fan_pin: 17,
|
fan_pin: 17,
|
||||||
fan_on_temp_c: 40.0,
|
fan_on_temp_c: 35.0,
|
||||||
fan_off_temp_c: 35.0,
|
fan_off_temp_c: 30.0,
|
||||||
poll_interval_s: 2.0,
|
poll_interval_s: 2.0,
|
||||||
thermal_alarm_temp_c: 80.0,
|
thermal_alarm_temp_c: 80.0,
|
||||||
influx: InfluxConfig::from_env(),
|
influx: InfluxConfig::from_env(),
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ pub async fn run(config: Config) -> anyhow::Result<()> {
|
|||||||
result = tasks::status::run(config.status_pin, status_rx) => {
|
result = tasks::status::run(config.status_pin, status_rx) => {
|
||||||
result?;
|
result?;
|
||||||
}
|
}
|
||||||
result = tasks::thermal::run(config.clone(), fan.clone(), alarms.clone()) => {
|
result = tasks::thermal::run(config.clone(), alarms.clone()) => {
|
||||||
result?;
|
result?;
|
||||||
}
|
}
|
||||||
result = async {
|
result = async {
|
||||||
@@ -44,6 +44,9 @@ pub async fn run(config: Config) -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
result = tasks::renogy::run(
|
result = tasks::renogy::run(
|
||||||
config.renogy.clone(),
|
config.renogy.clone(),
|
||||||
|
config.fan_on_temp_c,
|
||||||
|
config.fan_off_temp_c,
|
||||||
|
fan.clone(),
|
||||||
config.influx.clone(),
|
config.influx.clone(),
|
||||||
alarms.clone(),
|
alarms.clone(),
|
||||||
) => {
|
) => {
|
||||||
|
|||||||
@@ -8,12 +8,16 @@ use tracing::{debug, info, warn};
|
|||||||
|
|
||||||
use crate::alarm::SharedAlarms;
|
use crate::alarm::SharedAlarms;
|
||||||
use crate::config::{InfluxConfig, RenogyConfig};
|
use crate::config::{InfluxConfig, RenogyConfig};
|
||||||
|
use crate::gpio::{Fan, SharedFan};
|
||||||
use crate::renogy::{self, Client as RenogyClient, ControllerData, ControllerInfo};
|
use crate::renogy::{self, Client as RenogyClient, ControllerData, ControllerInfo};
|
||||||
|
|
||||||
const RECONNECT_INTERVAL_S: f64 = 15.0;
|
const RECONNECT_INTERVAL_S: f64 = 15.0;
|
||||||
|
|
||||||
pub async fn run(
|
pub async fn run(
|
||||||
config: RenogyConfig,
|
config: RenogyConfig,
|
||||||
|
fan_on_temp_c: f64,
|
||||||
|
fan_off_temp_c: f64,
|
||||||
|
fan: SharedFan,
|
||||||
influx: Option<InfluxConfig>,
|
influx: Option<InfluxConfig>,
|
||||||
alarms: SharedAlarms,
|
alarms: SharedAlarms,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
@@ -43,7 +47,16 @@ pub async fn run(
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
match connect_and_poll(&port, &config, influx.as_ref(), &alarms).await {
|
match connect_and_poll(
|
||||||
|
&port,
|
||||||
|
&config,
|
||||||
|
fan_on_temp_c,
|
||||||
|
fan_off_temp_c,
|
||||||
|
&fan,
|
||||||
|
influx.as_ref(),
|
||||||
|
&alarms,
|
||||||
|
)
|
||||||
|
.await {
|
||||||
Ok(()) => return Ok(()),
|
Ok(()) => return Ok(()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
alarms.set_fault("renogy", true).await;
|
alarms.set_fault("renogy", true).await;
|
||||||
@@ -57,6 +70,9 @@ pub async fn run(
|
|||||||
async fn connect_and_poll(
|
async fn connect_and_poll(
|
||||||
port: &str,
|
port: &str,
|
||||||
config: &RenogyConfig,
|
config: &RenogyConfig,
|
||||||
|
fan_on_temp_c: f64,
|
||||||
|
fan_off_temp_c: f64,
|
||||||
|
fan: &SharedFan,
|
||||||
influx: Option<&InfluxConfig>,
|
influx: Option<&InfluxConfig>,
|
||||||
alarms: &SharedAlarms,
|
alarms: &SharedAlarms,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
@@ -104,13 +120,23 @@ async fn connect_and_poll(
|
|||||||
// Clear fault
|
// Clear fault
|
||||||
alarms.set_fault("renogy", false).await;
|
alarms.set_fault("renogy", false).await;
|
||||||
|
|
||||||
// Debug log
|
{
|
||||||
debug!(
|
let mut fan = fan.lock().await;
|
||||||
battery_v = data.battery_voltage,
|
update_fan(
|
||||||
battery_soc = data.battery_soc,
|
&mut fan,
|
||||||
solar_w = data.solar_watts,
|
fan_on_temp_c,
|
||||||
"Renogy poll ok"
|
fan_off_temp_c,
|
||||||
);
|
data.controller_temperature_c,
|
||||||
|
);
|
||||||
|
debug!(
|
||||||
|
battery_v = data.battery_voltage,
|
||||||
|
battery_soc = data.battery_soc,
|
||||||
|
controller_temp_c = data.controller_temperature_c,
|
||||||
|
solar_w = data.solar_watts,
|
||||||
|
fan = if fan.on() { "on" } else { "off" },
|
||||||
|
"Renogy poll ok"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Publish data
|
// Publish data
|
||||||
if let (Some(client), Some(influx)) = (&influx_client, influx) {
|
if let (Some(client), Some(influx)) = (&influx_client, influx) {
|
||||||
@@ -124,6 +150,25 @@ async fn connect_and_poll(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_fan(fan: &mut Fan, on_temp_c: f64, off_temp_c: f64, controller_temp_c: u8) {
|
||||||
|
let temp_c = f64::from(controller_temp_c);
|
||||||
|
if !fan.on() && temp_c > on_temp_c {
|
||||||
|
fan.set_on(true);
|
||||||
|
info!(
|
||||||
|
controller_temp_c = temp_c,
|
||||||
|
threshold = on_temp_c,
|
||||||
|
"Fan on"
|
||||||
|
);
|
||||||
|
} else if fan.on() && temp_c <= off_temp_c {
|
||||||
|
fan.set_on(false);
|
||||||
|
info!(
|
||||||
|
controller_temp_c = temp_c,
|
||||||
|
threshold = off_temp_c,
|
||||||
|
"Fan off"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Publish data to InfluxDB
|
// Publish data to InfluxDB
|
||||||
async fn publish(
|
async fn publish(
|
||||||
client: &InfluxClient,
|
client: &InfluxClient,
|
||||||
|
|||||||
@@ -1,57 +1,26 @@
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use tokio::time::MissedTickBehavior;
|
use tokio::time::MissedTickBehavior;
|
||||||
use tracing::{debug, info};
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::alarm::SharedAlarms;
|
use crate::alarm::SharedAlarms;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::gpio::{Fan, SharedFan};
|
|
||||||
use crate::thermal;
|
use crate::thermal;
|
||||||
|
|
||||||
pub async fn run(config: Config, fan: SharedFan, alarms: SharedAlarms) -> anyhow::Result<()> {
|
pub async fn run(config: Config, alarms: SharedAlarms) -> anyhow::Result<()> {
|
||||||
// Setup the interval for the thermal task
|
|
||||||
let mut interval =
|
let mut interval =
|
||||||
tokio::time::interval(Duration::from_secs_f64(config.poll_interval_s));
|
tokio::time::interval(Duration::from_secs_f64(config.poll_interval_s));
|
||||||
interval.set_missed_tick_behavior(MissedTickBehavior::Skip);
|
interval.set_missed_tick_behavior(MissedTickBehavior::Skip);
|
||||||
|
|
||||||
loop { // Main loop
|
loop {
|
||||||
interval.tick().await;
|
interval.tick().await;
|
||||||
|
|
||||||
// Read the temperature
|
|
||||||
let temp_c = tokio::task::spawn_blocking(thermal::read_cpu_temp_c)
|
let temp_c = tokio::task::spawn_blocking(thermal::read_cpu_temp_c)
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
// Check if the temperature is over the alarm threshold
|
|
||||||
let over_temp = temp_c >= config.thermal_alarm_temp_c;
|
let over_temp = temp_c >= config.thermal_alarm_temp_c;
|
||||||
alarms.set_fault("thermal", over_temp).await;
|
alarms.set_fault("thermal", over_temp).await;
|
||||||
|
|
||||||
// Update the fan
|
debug!(temp_c, alarm = ?alarms.status());
|
||||||
let mut fan = fan.lock().await;
|
|
||||||
update_fan(&mut fan, &config, temp_c);
|
|
||||||
|
|
||||||
// Debug logging
|
|
||||||
debug!(
|
|
||||||
temp_c,
|
|
||||||
fan = if fan.on() { "on" } else { "off" },
|
|
||||||
alarm = ?alarms.status(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_fan(fan: &mut Fan, config: &Config, temp_c: f64) {
|
|
||||||
if !fan.on() && temp_c >= config.fan_on_temp_c {
|
|
||||||
fan.set_on(true);
|
|
||||||
info!(
|
|
||||||
temp_c,
|
|
||||||
threshold = config.fan_on_temp_c,
|
|
||||||
"Fan on"
|
|
||||||
);
|
|
||||||
} else if fan.on() && temp_c <= config.fan_off_temp_c {
|
|
||||||
fan.set_on(false);
|
|
||||||
info!(
|
|
||||||
temp_c,
|
|
||||||
threshold = config.fan_off_temp_c,
|
|
||||||
"Fan off"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Tower Daemon
|
Description=Tower Daemon
|
||||||
After=multi-user.target docker.service
|
After=multi-user.target influxdb.service
|
||||||
Wants=docker.service
|
Wants=influxdb.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
|
|||||||
Reference in New Issue
Block a user