link to device entity details from customization page

This commit is contained in:
Proddy
2022-07-24 13:39:52 +02:00
parent d0bcbb8d1b
commit d12879b07b
4 changed files with 41 additions and 44 deletions

View File

@@ -13,7 +13,8 @@ import {
ToggleButtonGroup, ToggleButtonGroup,
Tooltip, Tooltip,
Grid, Grid,
TextField TextField,
Link
} from '@mui/material'; } from '@mui/material';
import { Table } from '@table-library/react-table-library/table'; import { Table } from '@table-library/react-table-library/table';
@@ -26,11 +27,6 @@ import { useSnackbar } from 'notistack';
import SaveIcon from '@mui/icons-material/Save'; import SaveIcon from '@mui/icons-material/Save';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
// import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
// import StarIcon from '@mui/icons-material/Star';
// import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
// import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore'; import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore';
import KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutlined'; import KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutlined';
import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined'; import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';
@@ -48,13 +44,15 @@ import { extractErrorMessage } from '../utils';
import { DeviceShort, Devices, DeviceEntity, DeviceEntityMask } from './types'; import { DeviceShort, Devices, DeviceEntity, DeviceEntityMask } from './types';
export const APIURL = window.location.origin + '/api/';
const SettingsCustomization: FC = () => { const SettingsCustomization: FC = () => {
const { enqueueSnackbar } = useSnackbar(); const { enqueueSnackbar } = useSnackbar();
const [deviceEntities, setDeviceEntities] = useState<DeviceEntity[]>([{ id: '', v: 0, n: '', m: 0, w: false }]); const [deviceEntities, setDeviceEntities] = useState<DeviceEntity[]>([{ id: '', v: 0, n: '', m: 0, w: false }]);
const [devices, setDevices] = useState<Devices>(); const [devices, setDevices] = useState<Devices>();
const [errorMessage, setErrorMessage] = useState<string>(); const [errorMessage, setErrorMessage] = useState<string>();
const [selectedDevice, setSelectedDevice] = useState<number>(0); const [selectedDevice, setSelectedDevice] = useState<number>(-1);
const [confirmReset, setConfirmReset] = useState<boolean>(false); const [confirmReset, setConfirmReset] = useState<boolean>(false);
const [selectedFilters, setSelectedFilters] = useState<number>(0); const [selectedFilters, setSelectedFilters] = useState<number>(0);
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
@@ -94,7 +92,6 @@ const SettingsCustomization: FC = () => {
Row: ` Row: `
background-color: #1e1e1e; background-color: #1e1e1e;
position: relative; position: relative;
cursor: pointer;
.td { .td {
border-top: 1px solid #565656; border-top: 1px solid #565656;
@@ -107,11 +104,6 @@ const SettingsCustomization: FC = () => {
font-weight: normal; font-weight: normal;
} }
&:hover .td {
border-top: 1px solid #177ac9;
border-bottom: 1px solid #177ac9;
}
&:nth-of-type(odd) .td { &:nth-of-type(odd) .td {
background-color: #303030; background-color: #303030;
} }
@@ -194,7 +186,15 @@ const SettingsCustomization: FC = () => {
} else if (de.n === '') { } else if (de.n === '') {
return 'Command: ' + de.id; return 'Command: ' + de.id;
} }
return de.n + ' (' + de.id + ')'; return (
<>
{de.n}&nbsp;(
<Link target="_blank" href={APIURL + devices?.devices[selectedDevice].t + '/' + de.id}>
{de.id}
</Link>
)
</>
);
} }
const getMaskNumber = (newMask: string[]) => { const getMaskNumber = (newMask: string[]) => {
@@ -239,20 +239,12 @@ const SettingsCustomization: FC = () => {
); );
}; };
function compareDevices(a: DeviceShort, b: DeviceShort) {
if (a.s < b.s) {
return -1;
}
if (a.s > b.s) {
return 1;
}
return 0;
}
const changeSelectedDevice = (event: React.ChangeEvent<HTMLInputElement>) => { const changeSelectedDevice = (event: React.ChangeEvent<HTMLInputElement>) => {
const selected_device = parseInt(event.target.value, 10); if (devices) {
setSelectedDevice(selected_device); const selected_device = parseInt(event.target.value, 10);
fetchDeviceEntities(selected_device); setSelectedDevice(selected_device);
fetchDeviceEntities(devices?.devices[selected_device].i);
}
}; };
const resetCustomization = async () => { const resetCustomization = async () => {
@@ -267,7 +259,7 @@ const SettingsCustomization: FC = () => {
}; };
const saveCustomization = async () => { const saveCustomization = async () => {
if (deviceEntities && selectedDevice) { if (devices && deviceEntities && selectedDevice !== -1) {
const masked_entities = deviceEntities const masked_entities = deviceEntities
.filter((de) => de.m !== de.om) .filter((de) => de.m !== de.om)
.map((new_de) => new_de.m.toString(16).padStart(2, '0') + new_de.id); .map((new_de) => new_de.m.toString(16).padStart(2, '0') + new_de.id);
@@ -279,7 +271,7 @@ const SettingsCustomization: FC = () => {
try { try {
const response = await EMSESP.writeMaskedEntities({ const response = await EMSESP.writeMaskedEntities({
id: selectedDevice, id: devices?.devices[selectedDevice].i,
entity_ids: masked_entities entity_ids: masked_entities
}); });
if (response.status === 200) { if (response.status === 200) {
@@ -305,13 +297,13 @@ const SettingsCustomization: FC = () => {
<Typography variant="body2">Select a device and customize each of its entities using the options:</Typography> <Typography variant="body2">Select a device and customize each of its entities using the options:</Typography>
<Typography variant="body2"> <Typography variant="body2">
<OptionIcon type="favorite" isSet={true} /> <OptionIcon type="favorite" isSet={true} />
=mark as a favorite&nbsp;&nbsp; =mark as favorite&nbsp;&nbsp;
<OptionIcon type="readonly" isSet={true} /> <OptionIcon type="readonly" isSet={true} />
=disable write action&nbsp;&nbsp; =disable write action&nbsp;&nbsp;
<OptionIcon type="api_mqtt_exclude" isSet={true} /> <OptionIcon type="api_mqtt_exclude" isSet={true} />
=exclude from MQTT and API outputs&nbsp;&nbsp; =exclude from MQTT and API&nbsp;&nbsp;
<OptionIcon type="web_exclude" isSet={true} /> <OptionIcon type="web_exclude" isSet={true} />
=hide from Web Dashboard =hide from Dashboard
</Typography> </Typography>
</Box> </Box>
<ValidatedTextField <ValidatedTextField
@@ -324,11 +316,11 @@ const SettingsCustomization: FC = () => {
margin="normal" margin="normal"
select select
> >
<MenuItem disabled key={0} value={0}> <MenuItem disabled key={0} value={-1}>
Select a device... Select a device...
</MenuItem> </MenuItem>
{devices.devices.sort(compareDevices).map((device: DeviceShort, index) => ( {devices.devices.map((device: DeviceShort, index) => (
<MenuItem key={index} value={device.i}> <MenuItem key={index} value={index}>
{device.s} {device.s}
</MenuItem> </MenuItem>
))} ))}

View File

@@ -104,9 +104,10 @@ export interface CoreData {
export interface DeviceShort { export interface DeviceShort {
i: number; // id i: number; // id
d: number; // deviceid d?: number; // deviceid
p: number; // productid p?: number; // productid
s: string; // shortname s: string; // shortname
t?: string; // device type name
} }
export interface Devices { export interface Devices {

View File

@@ -347,18 +347,21 @@ const emsesp_devices = {
d: 23, d: 23,
p: 77, p: 77,
s: 'Thermostat (RC20/Moduline 300)', s: 'Thermostat (RC20/Moduline 300)',
t: 'thermostat1',
}, },
{ {
i: 2, i: 2,
d: 8, d: 8,
p: 123, p: 123,
s: 'Boiler (Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i)', s: 'Boiler (Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i)',
t: 'boiler',
}, },
{ {
i: 4, i: 4,
d: 16, d: 16,
p: 165, p: 165,
s: 'Thermostat (RC100/Moduline 1000/1010)', s: 'Thermostat (RC100/Moduline 1000/1010)',
t: 'thermostat2',
}, },
], ],
} }
@@ -1224,8 +1227,8 @@ rest_server.get(GET_CUSTOMIZATIONS_ENDPOINT, (req, res) => {
// start server // start server
const expressServer = rest_server.listen(port, () => const expressServer = rest_server.listen(port, () =>
console.log(`EMS-ESP REST API server running on http://localhost:${port}/api`),
) )
console.log(`EMS-ESP Rest API listening to http://localhost:${port}/api`)
// start websocket server // start websocket server
const websocketServer = new WebSocket.Server({ const websocketServer = new WebSocket.Server({

View File

@@ -165,22 +165,23 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN); auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN);
JsonObject root = response->getRoot(); JsonObject root = response->getRoot();
// list is already sorted by device type
// controller is ignored since it doesn't have any associated entities
JsonArray devices = root.createNestedArray("devices"); JsonArray devices = root.createNestedArray("devices");
for (const auto & emsdevice : EMSESP::emsdevices) { for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice->has_entities()) { if (emsdevice->has_entities()) {
JsonObject obj = devices.createNestedObject(); JsonObject obj = devices.createNestedObject();
obj["i"] = emsdevice->unique_id(); // a unique id obj["i"] = emsdevice->unique_id(); // its unique id
obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")"; // shortname
/* // device type name. We may have one than one (e.g. multiple thermostats) so postfix name with index
uint8_t device_index = EMSESP::device_index(emsdevice->device_type(), emsdevice->unique_id()); uint8_t device_index = EMSESP::device_index(emsdevice->device_type(), emsdevice->unique_id());
if (device_index) { if (device_index) {
char s[10]; char s[10];
obj["s"] = emsdevice->device_type_name() + Helpers::smallitoa(s, device_index) + " (" + emsdevice->name() + ")"; // shortname - we prefix the count to make it unique obj["t"] = Helpers::toLower(emsdevice->device_type_name()) + Helpers::smallitoa(s, device_index);
} else { } else {
obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")"; obj["t"] = Helpers::toLower(emsdevice->device_type_name());
} }
*/
obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")";
} }
} }