Skip to content

Commit 0b7f2a3

Browse files
committed
Gracefully handle ambient and heaters missing
1 parent 5dee0c0 commit 0b7f2a3

14 files changed

Lines changed: 115 additions & 25 deletions

File tree

src/ambient/ambient-none.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "ambient-p.h"
2+
#ifdef APB_AMBIENT_TEMPERATURE_SENSOR_NONE
3+
4+
5+
6+
bool APB::Ambient::initialiseSensor() {
7+
Log.infoln(LOG_SCOPE "No Ambient sensor installed");
8+
return false;
9+
}
10+
11+
void APB::Ambient::readSensor() {
12+
}
13+
14+
#endif
15+

src/configuration.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
#define APB_HEATER_TEMPERATURE_SENSOR_THERMISTOR_NOMINAL 10'000
2121
#define APB_HEATER_TEMPERATURE_SENSOR_THERMISTOR_NOMINAL_TEMP 25
2222
#define APB_HEATER_TEMPERATURE_SENSOR_THERMISTOR_B_VALUE 3950
23-
#define APB_POWER_MAX_CURRENT_AMPS 15
23+
#define APB_POWER_MAX_CURRENT_AMPS 8
2424
#define APB_POWER_SHUNT_OHMS 0.040
25+
#define APB_POWER_INA219_GAIN 8
26+
#define APB_POWER_INA219_VOLTAGE_RANGE 16
2527
#define APB_HISTORY_TASK_SECONDS 10'000
2628

2729
#define APB_AMBIENT_TEMPERATURE_SENSOR_SHT4x

src/history.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,20 @@ APB::History::History() {
1010
}
1111

1212

13+
#if APB_HEATERS_SIZE > 0
1314
void APB::History::Entry::Heater::set(const APB::Heater &heater) {
1415
temperatureHundredth = static_cast<int16_t>(heater.temperature().value_or(-100.0) * 100.0);
1516
duty = heater.active() ? heater.duty() : 0;
1617
}
18+
#endif
1719

20+
#ifndef APB_AMBIENT_TEMPERATURE_SENSOR_NONE
1821
void APB::History::Entry::setAmbient(const std::optional<Ambient::Reading> &reading) {
1922
const auto readingValue = reading.value_or(Ambient::Reading{-100.0, -100.0});
2023
ambientTemperatureHundredth = static_cast<uint16_t>(readingValue.temperature * 100.0);
2124
ambientHumidityHundredth = static_cast<uint16_t>(readingValue.humidity * 100.0);
2225
}
26+
#endif
2327

2428
void APB::History::Entry::setPower(const PowerMonitor::Status & powerStatus) {
2529
busVoltageHundreth = static_cast<uint16_t>(powerStatus.busVoltage * 100.0);
@@ -28,14 +32,26 @@ void APB::History::Entry::setPower(const PowerMonitor::Status & powerStatus) {
2832

2933
void APB::History::Entry::populate(JsonObject object) {
3034
object["uptime"] = secondsFromBoot;
35+
36+
#ifndef APB_AMBIENT_TEMPERATURE_SENSOR_NONE
3137
setNullableFloat(object, "ambientTemperature", getAmbientTemperature());
3238
setNullableFloat(object, "ambientHumidity", getAmbientHumidity());
3339
object["ambientDewpoint"] = getDewpoint();
40+
#else
41+
object["ambientTemperature"] = static_cast<char*>(0);
42+
object["ambientHumidity"] = static_cast<char*>(0);
43+
object["ambientDewpoint"] = static_cast<char*>(0);
44+
#endif
45+
46+
#if APB_HEATERS_SIZE > 0
3447
for(uint8_t i=0; i<heaters.size(); i++) {
3548
JsonObject heaterObject = object["heaters"][i].to<JsonObject>();;
3649
heaterObject["duty"] = heaters[i].getDuty();
3750
setNullableFloat(heaterObject, "temperature", heaters[i].getTemperature());
3851
}
52+
#else
53+
object["heaters"].to<JsonArray>();
54+
#endif
3955
object["busVoltage"] = getBusVoltage();
4056
object["power"] = getPower();
4157
object["current"] = getCurrent();

src/history.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,35 @@ class History {
2020
public:
2121
History();
2222
struct Entry {
23+
#if APB_HEATERS_SIZE > 0
2324
struct Heater {
2425
int16_t temperatureHundredth;
2526
uint8_t duty;
2627
void set(const APB::Heater &heater);
2728
float getTemperature() const { return static_cast<float>(temperatureHundredth) / 100.0; }
2829
float getDuty() const { return static_cast<float>(duty); }
2930
};
31+
std::array<Heater, APB_HEATERS_TEMP_SENSORS> heaters;
32+
#endif
3033
uint32_t secondsFromBoot;
34+
#ifndef APB_AMBIENT_TEMPERATURE_SENSOR_NONE
3135
void setAmbient(const std::optional<Ambient::Reading> &reading);
32-
void setPower(const PowerMonitor::Status &powerStatus);
33-
36+
float getAmbientTemperature() const { return static_cast<float>(ambientTemperatureHundredth) / 100.0; }
37+
float getAmbientHumidity() const { return static_cast<float>(ambientHumidityHundredth) / 100.0; }
38+
float getDewpoint() const { return Ambient::calculateDewpoint(getAmbientTemperature(), getAmbientHumidity()); }
3439
int16_t ambientTemperatureHundredth;
3540
int16_t ambientHumidityHundredth;
41+
#endif
42+
void setPower(const PowerMonitor::Status &powerStatus);
43+
3644
int16_t busVoltageHundreth;
3745
int16_t currentHundreth;
3846

39-
float getAmbientTemperature() const { return static_cast<float>(ambientTemperatureHundredth) / 100.0; }
40-
float getAmbientHumidity() const { return static_cast<float>(ambientHumidityHundredth) / 100.0; }
41-
float getDewpoint() const { return Ambient::calculateDewpoint(getAmbientTemperature(), getAmbientHumidity()); }
42-
47+
4348
float getBusVoltage() const { return static_cast<float>(busVoltageHundreth) / 100.0; }
4449
float getCurrent() const { return static_cast<float>(currentHundreth) / 100.0; }
4550
float getPower() const { return getCurrent() * getBusVoltage(); }
46-
std::array<Heater, APB_HEATERS_TEMP_SENSORS> heaters;
51+
4752

4853
void populate(JsonObject object);
4954

src/main.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,16 @@ void addHistoryEntry() {
124124
APB::History::Entry entry {
125125
esp_timer_get_time() / 1000'000
126126
};
127+
128+
#ifndef APB_AMBIENT_TEMPERATURE_SENSOR_NONE
127129
entry.setAmbient(APB::Ambient::Instance.reading());
130+
#endif
131+
132+
#if APB_HEATERS_SIZE > 0
128133
for(uint8_t i=0; i<APB_HEATERS_TEMP_SENSORS; i++) {
129134
entry.heaters[i].set(APB::Heaters::Instance[i]);
130135
}
136+
#endif
131137
entry.setPower(APB::PowerMonitor::Instance.status());
132138
APB::History::Instance.add(entry);
133139
}

src/webserver.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,12 @@ void APB::WebServer::setup() {
6868

6969
new Task(1000, TASK_FOREVER, [this](){
7070
eventsDocument.clear();
71-
populateAmbientStatus(eventsDocument.createNestedObject("ambient"));
71+
if(Ambient::Instance.isInitialised()) {
72+
populateAmbientStatus(eventsDocument.createNestedObject("ambient"));
73+
} else {
74+
eventsDocument["ambient"] = static_cast<char*>(0);
75+
}
76+
7277
populatePowerStatus(eventsDocument.createNestedObject("power"));
7378
populateHeatersStatus(eventsDocument.createNestedArray("heaters"));
7479
eventsDocument["app"]["uptime"] = esp_timer_get_time() / 1000'000.0;

web/src/App.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { setAmbient } from './features/sensors/ambient/ambientSlice';
44
import { useDispatch, useSelector } from 'react-redux';
55
import { getHeatersAsync, updateHeaters } from './features/sensors/heaters/heatersSlice';
66
import { setPower } from './features/sensors/power/powerSlice';
7-
import { darkModeSelector, getHistoryAsync, setUptime, tabSelector } from './features/app/appSlice';
7+
import { darkModeSelector, getAppStatusAsync, getHistoryAsync, setUptime, tabSelector } from './features/app/appSlice';
88
import Tab from 'react-bootstrap/Tab';
99
import Container from 'react-bootstrap/Container';
1010
import { Home } from './features/Home';
@@ -15,8 +15,13 @@ const registerEventSource = dispatch => {
1515
const es = new EventSource('/api/events');
1616
es.addEventListener('status', m => {
1717
const data = JSON.parse(m.data);
18-
dispatch(setAmbient(data.ambient));
19-
dispatch(updateHeaters(data.heaters));
18+
if(data.ambient) {
19+
dispatch(setAmbient(data.ambient));
20+
}
21+
if(data.heaters.length > 0) {
22+
dispatch(updateHeaters(data.heaters));
23+
}
24+
2025
dispatch(setPower(data.power));
2126
dispatch(setUptime(data.app.uptime));
2227
})
@@ -29,6 +34,7 @@ const LightMode = () => <link rel="stylesheet" type="text/css" href='flatly.min.
2934
function App() {
3035
const dispatch = useDispatch();
3136
const darkMode = useSelector(darkModeSelector)
37+
useEffect(() => { dispatch(getAppStatusAsync()) }, [dispatch])
3238
useEffect(() => { dispatch(getHistoryAsync()) }, [dispatch])
3339
useEffect(() => { dispatch(getHeatersAsync()) }, [dispatch])
3440
useEffect(() => registerEventSource(dispatch), [dispatch]);

web/src/features/Home.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
1+
import { useSelector } from "react-redux"
12
import { Ambient } from "./sensors/ambient/Ambient"
23
import { Heaters } from "./sensors/heaters/Heaters"
34
import { Power } from "./sensors/power/Power"
5+
import { selectHeatersCount } from "./sensors/heaters/heatersSlice"
6+
import { appStatusSelector } from "./app/appSlice"
47

58
export const Home = () => {
9+
const heatersCount = useSelector(selectHeatersCount);
10+
const hasAmbient = useSelector(appStatusSelector).hasAmbientSensor
611
return <>
7-
<h2>Environment</h2>
8-
<Ambient />
9-
<h2 className="mt-5">Heaters</h2>
10-
<Heaters />
11-
<h2 className="mt-5">Power</h2>
12+
{ hasAmbient && <>
13+
<h2 className="mb-5">Environment</h2>
14+
<Ambient />
15+
</> }
16+
{ heatersCount > 0 && <>
17+
<h2 className="mb-5">Heaters</h2>
18+
<Heaters />
19+
</>
20+
}
21+
<h2 className="mb-5">Power</h2>
1222
<Power />
1323
</>
1424
}

web/src/features/app/api.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const payloadJson = async (path, method, payload) => {
2020
export const fetchHistory = async () => await fetchJson('/api/history')
2121
export const fetchHeaters = async () => await fetchJson('/api/heaters')
2222
export const fetchConfig = async () => await fetchJson('/api/config')
23+
export const fetchStatus = async () => await fetchJson('/api/status')
2324
export const saveConfig = async () => await fetchJson('/api/config/write', { method: 'POST'})
2425
export const saveWiFiAccessPointConfig = async payload => await payloadJson('/api/config/accessPoint', 'POST', payload)
2526
export const saveWiFiStationConfig = async payload => await payloadJson('/api/config/station', 'POST', payload)

web/src/features/app/appSlice.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,32 @@
11
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
2-
import { fetchAppInfo, fetchHistory, fetchReconnectWiFi, fetchRestart } from './api';
2+
import { fetchAppInfo, fetchHistory, fetchReconnectWiFi, fetchRestart, fetchStatus } from './api';
33

44
const initialState = {
55
tab: 'home',
66
darkMode: true,
77
info: {
88
ready: false,
99
uptime: 0,
10-
}
10+
},
11+
status: {}
1112
};
1213

1314
export const tabSelector = state => state.app.tab
1415
export const darkModeSelector = state => state.app.darkMode
1516
export const appInfoSelector = state => state.app.info
1617
export const appUptimeSelector = state => state.app.info.uptime
18+
export const appStatusSelector = state => state.app.status
1719

1820
export const getAppInfoAsync = createAsyncThunk(
1921
'app/getInfo',
2022
async () => await fetchAppInfo()
2123
);
2224

25+
export const getAppStatusAsync = createAsyncThunk(
26+
'app/getStatus',
27+
async () => await fetchStatus()
28+
);
29+
2330
export const getHistoryAsync = createAsyncThunk(
2431
'app/getHistory',
2532
async () => await fetchHistory()
@@ -46,6 +53,17 @@ export const appSlice = createSlice({
4653
},
4754
extraReducers: (builder) => {
4855
builder
56+
.addCase(getAppStatusAsync.pending, (state) => {
57+
state.status.ready = false
58+
})
59+
.addCase(getAppStatusAsync.fulfilled, (state, {payload: status}) => {
60+
state.status.ready = true;
61+
state.status.hasPowerMonitor = status.has_power_monitor;
62+
state.status.hasAmbientSensor = status.has_ambient_sensor;
63+
state.status.status = status.status;
64+
})
65+
66+
4967
.addCase(getAppInfoAsync.pending, (state) => {
5068
state.info.ready = false
5169
})

0 commit comments

Comments
 (0)