Skip to content

Commit a58cf83

Browse files
committed
Allow to configure led brightness and power source type from frontend
1 parent bde01da commit a58cf83

6 files changed

Lines changed: 76 additions & 7 deletions

File tree

web/src/App.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { darkModeSelector, getAppStatusAsync, getHistoryAsync, setUptime, tabSel
88
import Tab from 'react-bootstrap/Tab';
99
import Container from 'react-bootstrap/Container';
1010
import { Home } from './features/Home';
11-
import { WiFi } from './features/app/WiFi';
11+
import { Config } from './features/app/Config';
1212
import { System } from './features/app/System';
1313

1414
const registerEventSource = dispatch => {
@@ -48,7 +48,7 @@ function App() {
4848
<Tab.Container activeKey={activeTab}>
4949
<Tab.Content>
5050
<Tab.Pane eventKey='home'><Home /></Tab.Pane>
51-
<Tab.Pane eventKey='wifi'><WiFi /></Tab.Pane>
51+
<Tab.Pane eventKey='config'><Config /></Tab.Pane>
5252
<Tab.Pane eventKey='system'><System /></Tab.Pane>
5353
</Tab.Content>
5454
</Tab.Container>

web/src/AppNavbar.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const AppNavbar = () => {
2424
<Navbar.Collapse>
2525
<Nav variant='tabs' className='me-auto'>
2626
<NavTabItem eventKey='home' text='Home' />
27-
<NavTabItem eventKey='wifi' text='WiFi' />
27+
<NavTabItem eventKey='config' text='Configuration' />
2828
<NavTabItem eventKey='system' text='System' />
2929
<Nav.Item><Nav.Link href="/update" target="_blank">Update</Nav.Link></Nav.Item>
3030
</Nav>
Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import {
1111
saveStationConfigAsync,
1212
selectWiFiAccessPointConfig,
1313
selectConfig,
14-
selectWiFiStationsConfig
14+
selectWiFiStationsConfig,
15+
selectPowerSourceType,
16+
selectStatusLedDuty,
17+
setStatusLedDutyAsync,
18+
setPowerSourceTypeAsync
1519
} from './configSlice';
1620
import Spinner from 'react-bootstrap/Spinner';
1721
import { FaRegEye, FaRegEyeSlash } from "react-icons/fa";
@@ -22,6 +26,9 @@ import { ConfirmModal } from '../../ConfirmModal';
2226
import { reconnectWiFiAsync } from './appSlice';
2327
import { RestartModalButton } from './RestartModalButton';
2428
import { SaveConfigModalButton } from './SaveConfigModalButton';
29+
import { Number } from '../Number';
30+
import Badge from 'react-bootstrap/Badge';
31+
import { setPowerSourceType } from './api';
2532

2633
const WiFiPasswordControl = ({ label, ...props }) => {
2734
const [show, setShow] = useState(false);
@@ -105,7 +112,43 @@ const WiFiStations = () => {
105112
</Form>
106113
}
107114

108-
export const WiFi = () => {
115+
const AppSettings = () => {
116+
const dispatch = useDispatch();
117+
const upstreamPowerSourceType = useSelector(selectPowerSourceType);
118+
const upstreamLedBrightness = useSelector(selectStatusLedDuty);
119+
120+
const [ledBrightness, setLedBrightness] = useState(upstreamLedBrightness);
121+
const [powerSupply, setPowerSupply] = useState(upstreamPowerSourceType);
122+
useEffect(() => {
123+
setLedBrightness(upstreamLedBrightness);
124+
setPowerSupply(upstreamPowerSourceType);
125+
}, [setLedBrightness, setPowerSupply, upstreamLedBrightness, upstreamPowerSourceType]);
126+
127+
const updateLedBrightness = duty => {
128+
setLedBrightness(duty)
129+
dispatch(setStatusLedDutyAsync({duty}))
130+
}
131+
const updatePowerSourceType = powerSourceType => {
132+
setPowerSupply(powerSourceType);
133+
dispatch(setPowerSourceTypeAsync({powerSourceType}))
134+
}
135+
return <Form>
136+
<Form.Group className='mb-3'>
137+
<Form.Label>Status led brightness</Form.Label>
138+
<Badge className='float-end'><Number value={ledBrightness*100} decimals={0} unit='%' /></Badge>
139+
<Form.Range min={0.0} max={1.0} step={0.01} value={ledBrightness} onChange={e => updateLedBrightness(parseFloat(e.target.value))}/>
140+
</Form.Group>
141+
<Form.Group className='mb-3'>
142+
<Form.Label>Power supply</Form.Label>
143+
<Form.Select value={powerSupply} onChange={e => updatePowerSourceType(e.target.value)}>
144+
<option value="AC">AC</option>
145+
<option value="lipo_3c">LiPo Battery 3 cells (12v)</option>
146+
</Form.Select>
147+
</Form.Group>
148+
</Form>
149+
}
150+
151+
export const Config = () => {
109152
const dispatch = useDispatch();
110153
useEffect(() => { dispatch(getConfigAsync()) }, [dispatch])
111154
const wifiConfig = useSelector(selectConfig)
@@ -122,6 +165,9 @@ export const WiFi = () => {
122165
<Row className='mt-5'>
123166
<WiFiStations />
124167
</Row>
168+
<Row className='mt-5'>
169+
<AppSettings />
170+
</Row>
125171
<Row className='mt-5'>
126172
<Col sm={10}>Unsaved changes will be lost after restart. Save configuration to flash storage to persist them.</Col>
127173
<Col sm={2} className='d-grid'><SaveConfigModalButton /></Col>

web/src/features/app/api.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,5 @@ export const fetchAppInfo = async () => await fetchJson('/api/info')
2929
export const fetchRestart = async () => await fetchJson('/api/restart', { method: 'POST' })
3030
export const fetchReconnectWiFi = async () => await fetchJson('/api/wifi/connect', { method: 'POST' })
3131
export const setHeater = async (index, heater) => await payloadJson('/api/heater', 'POST', {index, ...heater})
32+
export const setStatusLedDuty = async payload => await payloadJson('/api/config/statusLedDuty', 'POST', payload)
33+
export const setPowerSourceType = async payload => await payloadJson('/api/config/powerSourceType', 'POST', payload)

web/src/features/app/configSlice.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createAsyncThunk, createSelector, createSlice } from '@reduxjs/toolkit';
2-
import { fetchConfig, removeWiFiStationConfig, saveConfig, saveWiFiAccessPointConfig, saveWiFiStationConfig } from './api';
2+
import { fetchConfig, removeWiFiStationConfig, saveConfig, saveWiFiAccessPointConfig, saveWiFiStationConfig, setPowerSourceType, setStatusLedDuty } from './api';
33

44
const initialState = {
55
ready: false,
@@ -8,6 +8,8 @@ const initialState = {
88
psk: '',
99
},
1010
stations: [],
11+
ledDuty: 1,
12+
powerSourceType: 'AC',
1113
};
1214

1315
export const getConfigAsync = createAsyncThunk(
@@ -36,11 +38,23 @@ export const saveConfigAsync = createAsyncThunk(
3638
async () => await saveConfig()
3739
);
3840

41+
export const setStatusLedDutyAsync = createAsyncThunk(
42+
'config/setStatusLedDuty',
43+
async ({duty}) => await setStatusLedDuty({ duty })
44+
)
45+
46+
export const setPowerSourceTypeAsync = createAsyncThunk(
47+
'config/setPowerSourceType',
48+
async ({powerSourceType}) => await setPowerSourceType({ powerSourceType })
49+
)
50+
51+
3952

4053

4154
export const selectConfig = state => state.config;
4255
export const selectConfigReady = createSelector([selectConfig], config => config.ready)
4356
export const selectPowerSourceType = createSelector([selectConfig], config => config.powerSourceType)
57+
export const selectStatusLedDuty = createSelector([selectConfig], config => config.ledDuty)
4458
export const selectWiFiAccessPointConfig = createSelector([selectConfig], config => config.accessPoint)
4559
export const selectWiFiStationsConfig = createSelector([selectConfig], config => config.stations)
4660

@@ -61,6 +75,13 @@ export const wifiSlice = createSlice({
6175
.addCase(saveConfigAsync.fulfilled, (_, {payload}) => ({...payload, ready: true}))
6276
.addCase(saveStationConfigAsync.fulfilled, (_, {payload}) => ({...payload, ready: true}))
6377
.addCase(removeStationConfigAsync.fulfilled, (_, {payload}) => ({...payload, ready: true}))
78+
.addCase(setPowerSourceTypeAsync.fulfilled, (state, {payload: {powerSourceType}}) => {
79+
state.powerSourceType = powerSourceType
80+
})
81+
.addCase(setStatusLedDutyAsync.fulfilled, (state, {payload: {duty}}) => {
82+
state.ledDuty = duty;
83+
})
84+
6485
},
6586
});
6687

web/src/features/sensors/power/Power.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Accordion from 'react-bootstrap/Accordion';
77
import { useId, useState } from 'react';
88
import { selectPowerSourceType } from '../../app/configSlice';
99

10-
const PowerChart= ({}) => {
10+
const PowerChart= () => {
1111
const id = useId();
1212
const history = useSelector(selectPowerHistory)
1313
const [selected, setSelected] = useState(null);

0 commit comments

Comments
 (0)