mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
replace disabled sensor gpio (99) with code logic
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useContext, useMemo, useState } from 'react';
|
import { useCallback, useContext, useMemo, useRef, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import AddCircleOutlineOutlinedIcon from '@mui/icons-material/AddCircleOutlineOutlined';
|
import AddCircleOutlineOutlinedIcon from '@mui/icons-material/AddCircleOutlineOutlined';
|
||||||
@@ -54,7 +54,6 @@ const MS_PER_SECOND = 1000;
|
|||||||
const MS_PER_MINUTE = 60 * MS_PER_SECOND;
|
const MS_PER_MINUTE = 60 * MS_PER_SECOND;
|
||||||
const MS_PER_HOUR = 60 * MS_PER_MINUTE;
|
const MS_PER_HOUR = 60 * MS_PER_MINUTE;
|
||||||
const MS_PER_DAY = 24 * MS_PER_HOUR;
|
const MS_PER_DAY = 24 * MS_PER_HOUR;
|
||||||
const DEFAULT_GPIO = 99; // not set
|
|
||||||
const MIN_TEMP_ID = -100;
|
const MIN_TEMP_ID = -100;
|
||||||
const MAX_TEMP_ID = 100;
|
const MAX_TEMP_ID = 100;
|
||||||
const GPIO_25 = 25;
|
const GPIO_25 = 25;
|
||||||
@@ -128,15 +127,21 @@ const Sensors = () => {
|
|||||||
const [temperatureDialogOpen, setTemperatureDialogOpen] = useState<boolean>(false);
|
const [temperatureDialogOpen, setTemperatureDialogOpen] = useState<boolean>(false);
|
||||||
const [analogDialogOpen, setAnalogDialogOpen] = useState<boolean>(false);
|
const [analogDialogOpen, setAnalogDialogOpen] = useState<boolean>(false);
|
||||||
const [creating, setCreating] = useState<boolean>(false);
|
const [creating, setCreating] = useState<boolean>(false);
|
||||||
|
const firstAvailableGPIO = useRef<number>(undefined);
|
||||||
|
|
||||||
const { data: sensorData, send: fetchSensorData } = useRequest(readSensorData, {
|
const { data: sensorData, send: fetchSensorData } = useRequest(readSensorData, {
|
||||||
initialData: {
|
initialData: {
|
||||||
ts: [],
|
ts: [],
|
||||||
as: [],
|
as: [],
|
||||||
analog_enabled: false,
|
analog_enabled: false,
|
||||||
valid_gpio_list: [],
|
valid_gpio_list: [] as number[],
|
||||||
platform: 'ESP32'
|
platform: 'ESP32'
|
||||||
}
|
}
|
||||||
|
}).onSuccess((event) => {
|
||||||
|
// store the first available GPIO in a ref
|
||||||
|
if (event.data.valid_gpio_list.length > 0) {
|
||||||
|
firstAvailableGPIO.current = event.data.valid_gpio_list[0];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { send: sendTemperatureSensor } = useRequest(
|
const { send: sendTemperatureSensor } = useRequest(
|
||||||
@@ -186,10 +191,14 @@ const Sensors = () => {
|
|||||||
sortToggleType: SortToggleType.AlternateWithReset,
|
sortToggleType: SortToggleType.AlternateWithReset,
|
||||||
sortFns: {
|
sortFns: {
|
||||||
GPIO: (array) =>
|
GPIO: (array) =>
|
||||||
[...array].sort((a, b) => (a as AnalogSensor).g - (b as AnalogSensor).g),
|
[...array].sort(
|
||||||
|
(a, b) => ((a as AnalogSensor)?.g ?? 0) - ((b as AnalogSensor)?.g ?? 0)
|
||||||
|
),
|
||||||
NAME: (array) =>
|
NAME: (array) =>
|
||||||
[...array].sort((a, b) =>
|
[...array].sort((a, b) =>
|
||||||
(a as AnalogSensor).n.localeCompare((b as AnalogSensor).n)
|
((a as AnalogSensor)?.n ?? '').localeCompare(
|
||||||
|
(b as AnalogSensor)?.n ?? ''
|
||||||
|
)
|
||||||
),
|
),
|
||||||
TYPE: (array) =>
|
TYPE: (array) =>
|
||||||
[...array].sort((a, b) => (a as AnalogSensor).t - (b as AnalogSensor).t),
|
[...array].sort((a, b) => (a as AnalogSensor).t - (b as AnalogSensor).t),
|
||||||
@@ -338,19 +347,23 @@ const Sensors = () => {
|
|||||||
}, [fetchSensorData]);
|
}, [fetchSensorData]);
|
||||||
|
|
||||||
const addAnalogSensor = useCallback(() => {
|
const addAnalogSensor = useCallback(() => {
|
||||||
|
if (firstAvailableGPIO.current === undefined) {
|
||||||
|
toast.error('No available GPIO found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
setCreating(true);
|
setCreating(true);
|
||||||
setSelectedAnalogSensor({
|
setSelectedAnalogSensor({
|
||||||
id: Math.floor(Math.random() * (MAX_TEMP_ID - MIN_TEMP_ID) + MIN_TEMP_ID),
|
id: Math.floor(Math.random() * (MAX_TEMP_ID - MIN_TEMP_ID) + MIN_TEMP_ID),
|
||||||
n: '',
|
n: '',
|
||||||
g: DEFAULT_GPIO,
|
g: firstAvailableGPIO.current,
|
||||||
u: 0,
|
u: DeviceValueUOM.NONE,
|
||||||
v: 0,
|
v: 0,
|
||||||
o: 0,
|
o: 0,
|
||||||
t: 0,
|
|
||||||
f: 1,
|
f: 1,
|
||||||
|
t: AnalogType.NOTUSED,
|
||||||
d: false,
|
d: false,
|
||||||
o_n: '',
|
s: false,
|
||||||
s: false
|
o_n: ''
|
||||||
});
|
});
|
||||||
setAnalogDialogOpen(true);
|
setAnalogDialogOpen(true);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -447,7 +460,7 @@ const Sensors = () => {
|
|||||||
item={as}
|
item={as}
|
||||||
onClick={() => updateAnalogSensor(as)}
|
onClick={() => updateAnalogSensor(as)}
|
||||||
>
|
>
|
||||||
<Cell stiff>{as.g !== 99 ? as.g : ''}</Cell>
|
<Cell stiff>{as.g}</Cell>
|
||||||
<Cell>{as.n}</Cell>
|
<Cell>{as.n}</Cell>
|
||||||
<Cell stiff>{AnalogTypeNames[as.t]} </Cell>
|
<Cell stiff>{AnalogTypeNames[as.t]} </Cell>
|
||||||
{(as.t === AnalogType.DIGITAL_OUT &&
|
{(as.t === AnalogType.DIGITAL_OUT &&
|
||||||
@@ -455,14 +468,10 @@ const Sensors = () => {
|
|||||||
as.g !== GPIO_26) ||
|
as.g !== GPIO_26) ||
|
||||||
as.t === AnalogType.DIGITAL_IN ||
|
as.t === AnalogType.DIGITAL_IN ||
|
||||||
as.t === AnalogType.PULSE ? (
|
as.t === AnalogType.PULSE ? (
|
||||||
<Cell stiff>
|
<Cell stiff>{as.v ? LL.ON() : LL.OFF()}</Cell>
|
||||||
{as.g !== 99 ? (as.v ? LL.ON() : LL.OFF()) : ''}
|
|
||||||
</Cell>
|
|
||||||
) : (
|
) : (
|
||||||
<Cell stiff>
|
<Cell stiff>
|
||||||
{as.t !== AnalogType.NOTUSED && as.g !== 99
|
{as.t !== AnalogType.NOTUSED ? formatValue(as.v, as.u) : ''}
|
||||||
? formatValue(as.v, as.u)
|
|
||||||
: ''}
|
|
||||||
</Cell>
|
</Cell>
|
||||||
)}
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
@@ -152,20 +152,6 @@ const SensorsAnalogDialog = ({
|
|||||||
[creating, LL]
|
[creating, LL]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ensure the current GPIO is in the list when no creating
|
|
||||||
// note GPIO 99 means not set
|
|
||||||
const availableGPIOs = useMemo(() => {
|
|
||||||
const filteredList = analogGPIOList.filter((gpio) => gpio !== 99);
|
|
||||||
if (
|
|
||||||
editItem.g !== undefined &&
|
|
||||||
editItem.g !== 99 &&
|
|
||||||
!filteredList.includes(editItem.g)
|
|
||||||
) {
|
|
||||||
return [...filteredList, editItem.g].sort((a, b) => a - b);
|
|
||||||
}
|
|
||||||
return filteredList;
|
|
||||||
}, [analogGPIOList, editItem.g]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog sx={dialogStyle} open={open} onClose={handleClose}>
|
<Dialog sx={dialogStyle} open={open} onClose={handleClose}>
|
||||||
<DialogTitle>{dialogTitle}</DialogTitle>
|
<DialogTitle>{dialogTitle}</DialogTitle>
|
||||||
@@ -175,12 +161,12 @@ const SensorsAnalogDialog = ({
|
|||||||
name="g"
|
name="g"
|
||||||
label="GPIO"
|
label="GPIO"
|
||||||
value={editItem.g}
|
value={editItem.g}
|
||||||
sx={{ width: '8ch' }}
|
sx={{ width: '9ch' }}
|
||||||
disabled={editItem.s}
|
disabled={editItem.s}
|
||||||
select
|
select
|
||||||
onChange={updateFormValue}
|
onChange={updateFormValue}
|
||||||
>
|
>
|
||||||
{availableGPIOs?.map((gpio: number) => (
|
{analogGPIOList?.map((gpio: number) => (
|
||||||
<MenuItem key={gpio} value={gpio}>
|
<MenuItem key={gpio} value={gpio}>
|
||||||
{gpio}
|
{gpio}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|||||||
@@ -89,15 +89,15 @@ export interface TemperatureSensor {
|
|||||||
export interface AnalogSensor {
|
export interface AnalogSensor {
|
||||||
id: number;
|
id: number;
|
||||||
g: number; // GPIO
|
g: number; // GPIO
|
||||||
n: string;
|
n: string; // name
|
||||||
v: number;
|
v: number; // value
|
||||||
u: number;
|
u: number; // uom
|
||||||
o: number;
|
o: number; // offset
|
||||||
f: number;
|
f: number; // factor
|
||||||
t: number;
|
t: number; // type
|
||||||
d: boolean; // deleted flag
|
d: boolean; // deleted flag
|
||||||
s: boolean; // system sensor flag
|
s: boolean; // system sensor flag
|
||||||
o_n?: string;
|
o_n?: string; // original name
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WriteTemperatureSensor {
|
export interface WriteTemperatureSensor {
|
||||||
|
|||||||
@@ -310,14 +310,6 @@ export const analogSensorItemValidation = (
|
|||||||
{ required: true, message: 'Name is required' },
|
{ required: true, message: 'Name is required' },
|
||||||
NAME_PATTERN,
|
NAME_PATTERN,
|
||||||
uniqueAnalogNameValidator(sensors, sensor.o_n)
|
uniqueAnalogNameValidator(sensors, sensor.o_n)
|
||||||
],
|
|
||||||
g: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
type: 'number',
|
|
||||||
min: 1,
|
|
||||||
message: 'GPIO is required'
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -987,7 +987,7 @@ const emsesp_sensordata = {
|
|||||||
{ id: 1, g: 35, n: 'motor', v: 0, u: 0, o: 17, f: 0, t: 0, d: false, s: false },
|
{ id: 1, g: 35, n: 'motor', v: 0, u: 0, o: 17, f: 0, t: 0, d: false, s: false },
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
g: 37,
|
g: 34,
|
||||||
n: 'External_switch',
|
n: 'External_switch',
|
||||||
v: 13,
|
v: 13,
|
||||||
u: 0,
|
u: 0,
|
||||||
@@ -1047,7 +1047,7 @@ const emsesp_sensordata = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
analog_enabled: true,
|
analog_enabled: true,
|
||||||
valid_gpio_list: [0, 2, 5, 12, 13, 15, 18, 19, 23, 25, 26, 27, 33, 37, 38]
|
valid_gpio_list: [] as number[]
|
||||||
};
|
};
|
||||||
|
|
||||||
const activity = {
|
const activity = {
|
||||||
@@ -4540,6 +4540,25 @@ router
|
|||||||
.get(EMSESP_SENSOR_DATA_ENDPOINT, () => {
|
.get(EMSESP_SENSOR_DATA_ENDPOINT, () => {
|
||||||
// random change the zolder temperature 0-100
|
// random change the zolder temperature 0-100
|
||||||
emsesp_sensordata.ts[2].t = Math.floor(Math.random() * 100);
|
emsesp_sensordata.ts[2].t = Math.floor(Math.random() * 100);
|
||||||
|
|
||||||
|
// Build list of available GPIOs (S3 board pins) excluding used ones
|
||||||
|
// and sort it
|
||||||
|
const allGPIOs = [2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 21, 33, 34, 35, 36, 37, 38, 45, 46];
|
||||||
|
const usedGPIOs = new Set([
|
||||||
|
settings.led_gpio,
|
||||||
|
settings.dallas_gpio,
|
||||||
|
settings.pbutton_gpio,
|
||||||
|
settings.rx_gpio,
|
||||||
|
settings.tx_gpio,
|
||||||
|
...emsesp_sensordata.as.map((item) => item.g)
|
||||||
|
]);
|
||||||
|
|
||||||
|
emsesp_sensordata.valid_gpio_list = allGPIOs
|
||||||
|
.filter((gpio) => !usedGPIOs.has(gpio))
|
||||||
|
.sort((a, b) => a - b);
|
||||||
|
|
||||||
|
// console.log('valid_gpio_list', emsesp_sensordata.valid_gpio_list);
|
||||||
|
|
||||||
return emsesp_sensordata;
|
return emsesp_sensordata;
|
||||||
})
|
})
|
||||||
.get(EMSESP_DEVICEDATA_ENDPOINT1, (request) =>
|
.get(EMSESP_DEVICEDATA_ENDPOINT1, (request) =>
|
||||||
|
|||||||
@@ -157,12 +157,13 @@ void AnalogSensor::reload(bool get_nvs) {
|
|||||||
if (!found) {
|
if (!found) {
|
||||||
// check if the GPIO is valid before registering. If not, force set the sensor to disabled, but don't remove it
|
// check if the GPIO is valid before registering. If not, force set the sensor to disabled, but don't remove it
|
||||||
// should only trigger if uploading a customization file with invalid gpios.
|
// should only trigger if uploading a customization file with invalid gpios.
|
||||||
|
AnalogType type = static_cast<AnalogType>(sensor.type);
|
||||||
if (!EMSESP::system_.is_valid_gpio(sensor.gpio)) {
|
if (!EMSESP::system_.is_valid_gpio(sensor.gpio)) {
|
||||||
LOG_WARNING("Bad GPIO %d for Sensor %s. Disabling.", sensor.gpio, sensor.name.c_str());
|
LOG_WARNING("Bad GPIO %d for Sensor %s. Disabling.", sensor.gpio, sensor.name.c_str());
|
||||||
sensors_.emplace_back(99, sensor.name, sensor.offset, sensor.factor, sensor.uom, sensor.type, sensor.is_system);
|
type = AnalogType::NOTUSED;
|
||||||
} else {
|
|
||||||
sensors_.emplace_back(sensor.gpio, sensor.name, sensor.offset, sensor.factor, sensor.uom, sensor.type, sensor.is_system);
|
|
||||||
}
|
}
|
||||||
|
sensors_.emplace_back(sensor.gpio, sensor.name, sensor.offset, sensor.factor, sensor.uom, type, sensor.is_system);
|
||||||
|
|
||||||
sensors_.back().ha_registered = false; // this will trigger recreate of the HA config
|
sensors_.back().ha_registered = false; // this will trigger recreate of the HA config
|
||||||
if (sensor.type == AnalogType::COUNTER || sensor.type >= AnalogType::DIGITAL_OUT) {
|
if (sensor.type == AnalogType::COUNTER || sensor.type >= AnalogType::DIGITAL_OUT) {
|
||||||
sensors_.back().set_value(sensor.offset);
|
sensors_.back().set_value(sensor.offset);
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) {
|
|||||||
obj["t"] = sensor.type();
|
obj["t"] = sensor.type();
|
||||||
obj["s"] = sensor.is_system();
|
obj["s"] = sensor.is_system();
|
||||||
|
|
||||||
if (sensor.type() != AnalogSensor::AnalogType::NOTUSED && sensor.gpio() != 99) {
|
if (sensor.type() != AnalogSensor::AnalogType::NOTUSED) {
|
||||||
obj["v"] = Helpers::transformNumFloat(sensor.value()); // is optional and is a float
|
obj["v"] = Helpers::transformNumFloat(sensor.value()); // is optional and is a float
|
||||||
} else {
|
} else {
|
||||||
obj["v"] = 0; // must have a value for web sorting to work
|
obj["v"] = 0; // must have a value for web sorting to work
|
||||||
@@ -436,7 +436,7 @@ void WebDataService::dashboard_data(AsyncWebServerRequest * request) {
|
|||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
for (const auto & sensor : EMSESP::analogsensor_.sensors()) {
|
for (const auto & sensor : EMSESP::analogsensor_.sensors()) {
|
||||||
// ignore system and disabled sensors
|
// ignore system and disabled sensors
|
||||||
if (sensor.is_system() || sensor.type() == AnalogSensor::AnalogType::NOTUSED || sensor.gpio() == 99) {
|
if (sensor.is_system() || sensor.type() == AnalogSensor::AnalogType::NOTUSED) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
JsonObject node = nodes.add<JsonObject>();
|
JsonObject node = nodes.add<JsonObject>();
|
||||||
|
|||||||
Reference in New Issue
Block a user