updates to data view

This commit is contained in:
Proddy
2023-05-11 18:19:47 +02:00
parent 6575e1d790
commit 4f8d3d27ba
15 changed files with 117 additions and 123 deletions

View File

@@ -25,6 +25,8 @@
"regex": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp"
"utility": "cpp",
"string": "cpp",
"string_view": "cpp"
}
}

View File

@@ -37,7 +37,6 @@ const de: Translation = {
BRAND: 'Marke',
ENTITY_NAME: 'Entitätsname',
VALUE: '{{Wert|wert}}',
SHOW_FAV: 'nur Favoriten anzeigen',
DEVICE_DATA: 'Gerätedaten',
SENSOR_DATA: 'Sensordaten',
DEVICES: 'Geräte',

View File

@@ -37,7 +37,6 @@ const en: Translation = {
BRAND: 'Brand',
ENTITY_NAME: 'Entity Name',
VALUE: '{{Value|value}}',
SHOW_FAV: 'only show favorites',
DEVICE_DATA: 'Device Data',
SENSOR_DATA: 'Sensor Data',
DEVICES: 'Devices',

View File

@@ -37,7 +37,6 @@ const fr: Translation = {
BRAND: 'Marque',
ENTITY_NAME: 'Nom de l\'entité',
VALUE: 'Valeur',
SHOW_FAV: 'ne montrer que les favoris',
DEVICE_DATA: 'Données des appareils',
SENSOR_DATA: 'Données des capteurs',
DEVICES: 'Appareils',

View File

@@ -37,7 +37,6 @@ const nl: Translation = {
BRAND: 'Merk',
ENTITY_NAME: 'Entiteit',
VALUE: '{{Waarde|waarde}}',
SHOW_FAV: 'alleen favorieten weergeven',
SENSOR_DATA: 'Sensor data',
DEVICE_DATA: 'Apparaat data',
DEVICES: 'Apparaten',

View File

@@ -37,7 +37,6 @@ const no: Translation = {
BRAND: 'Fabrikat',
ENTITY_NAME: 'Objektsnavn',
VALUE: '{{Verdi|verdi}}',
SHOW_FAV: ' Vis kun favoritter',
DEVICE_DATA: 'Enheterdata',
SENSOR_DATA: 'Sensordata',
DEVICES: 'Enheter',

View File

@@ -37,7 +37,6 @@ const pl: BaseTranslation = {
VERSION: 'Wersja',
ENTITY_NAME: 'Nazwa encji',
VALUE: '{{W|w|}}artość',
SHOW_FAV: 'Pokaż tylko "ulubione"',
DEVICE_DATA: 'Dane z urządzeń',
SENSOR_DATA: 'Dane z czujników',
DEVICES: 'Urządzenia',

View File

@@ -37,7 +37,6 @@ const sv: Translation = {
BRAND: 'Fabrikat',
ENTITY_NAME: 'Entitetsnamn',
VALUE: '{{Värde|värde}}',
SHOW_FAV: 'Visa enbart favoriter',
DEVICE_DATA: 'Enhets data',
SENSOR_DATA: 'Sensor data',
DEVICES: 'Enheter',

View File

@@ -37,7 +37,6 @@ const tr: Translation = {
BRAND: 'Marka',
ENTITY_NAME: 'Valık Adı',
VALUE: '{{Değer|değer}}',
SHOW_FAV: 'sadece favorileri göster',
DEVICE_DATA: 'Cihaz Bilgisi',
SENSOR_DATA: 'Sensör Bilgisi',
DEVICES: 'Cihazlar',

View File

@@ -9,6 +9,7 @@ import KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutl
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
import RefreshIcon from '@mui/icons-material/Refresh';
import StarIcon from '@mui/icons-material/Star';
import StarBorderOutlinedIcon from '@mui/icons-material/StarBorderOutlined';
import UnfoldMoreOutlinedIcon from '@mui/icons-material/UnfoldMoreOutlined';
import {
@@ -21,8 +22,6 @@ import {
List,
ListItem,
ListItemText,
FormControlLabel,
Checkbox,
Box,
Grid,
Typography
@@ -54,13 +53,15 @@ import { extractErrorMessage } from 'utils';
const DashboardDevices: FC = () => {
const { me } = useContext(AuthenticatedContext);
const { LL } = useI18nContext();
const [deviceData, setDeviceData] = useState<DeviceData>({ label: '', data: [] });
const [deviceData, setDeviceData] = useState<DeviceData>({ data: [] });
const [selectedDeviceValue, setSelectedDeviceValue] = useState<DeviceValue>();
const [deviceDetails, setDeviceDetails] = useState<number>(-1);
const [onlyFav, setOnlyFav] = useState(false);
const [selectedDevice, setSelectedDevice] = useState<number>();
const [deviceValueDialogOpen, setDeviceValueDialogOpen] = useState(false);
const [showDeviceInfo, setShowDeviceInfo] = useState<boolean>(false);
const [selectedDevice, setSelectedDevice] = useState<number>();
const [coreData, setCoreData] = useState<CoreData>({
connected: true,
devices: []
@@ -95,11 +96,6 @@ const DashboardDevices: FC = () => {
border-top: 1px solid #177ac9;
border-bottom: 1px solid #177ac9;
}
`,
Cell: `
&:last-of-type {
text-align: right;
},
`
});
@@ -107,7 +103,7 @@ const DashboardDevices: FC = () => {
common_theme,
{
Table: `
--data-table-library_grid-template-columns: 40px 160px repeat(1, minmax(0, 1fr)) 100px 40px;
--data-table-library_grid-template-columns: 40px 160px repeat(1, minmax(0, 1fr));
`,
BaseRow: `
.td {
@@ -136,7 +132,11 @@ const DashboardDevices: FC = () => {
Table: `
--data-table-library_grid-template-columns: 300px 150px 40px;
height: auto;
max-height: 92%;
max-height: 96%;
overflow-y: scroll;
::-webkit-scrollbar {
display:none;
}
`,
BaseCell: `
&:nth-of-type(2) {
@@ -192,6 +192,7 @@ const DashboardDevices: FC = () => {
};
function onSelectChange(action: any, state: any) {
setDeviceData({ data: [] });
setSelectedDevice(state.id);
if (action.type === 'ADD_BY_ID_EXCLUSIVELY') {
void fetchDeviceData(state.id);
@@ -205,13 +206,20 @@ const DashboardDevices: FC = () => {
}
);
const escFunction = useCallback((event) => {
const resetDeviceSelect = () => {
device_select.fns.onRemoveAll();
};
const escFunction = useCallback(
(event: any) => {
if (event.keyCode === 27) {
if (device_select) {
device_select.fns.onRemoveAll();
resetDeviceSelect();
}
}
}, []);
},
[device_select]
);
useEffect(() => {
document.addEventListener('keydown', escFunction);
@@ -288,10 +296,18 @@ const DashboardDevices: FC = () => {
},
{ accessor: (dv: any) => DeviceValueUOM_s[dv.u], name: 'UoM' }
];
// TODO create filename from selected device
const deviceIndex = coreData.devices.findIndex((d) => d.id === device_select.state.id);
if (deviceIndex === -1) {
return;
}
const filename = coreData.devices[deviceIndex].tn + '_' + coreData.devices[deviceIndex].n;
downloadAsCsv(
columns,
onlyFav ? deviceData.data.filter((dv) => hasMask(dv.id, DeviceEntityMask.DV_FAVORITE)) : deviceData.data,
'device_entities'
filename
);
};
@@ -326,42 +342,47 @@ const DashboardDevices: FC = () => {
};
const renderDeviceDetails = () => {
if (coreData && coreData.devices.length > 0 && deviceDetails !== -1) {
const device = coreData.devices[deviceDetails];
if (showDeviceInfo) {
// find record based on device_seelct.state.id
const deviceIndex = coreData.devices.findIndex((d) => d.id === device_select.state.id);
if (deviceIndex === -1) {
return;
}
return (
<Dialog open={deviceDetails !== -1} onClose={() => setDeviceDetails(-1)}>
<Dialog open={showDeviceInfo} onClose={() => setShowDeviceInfo(false)}>
<DialogTitle>{LL.DEVICE_DETAILS()}</DialogTitle>
<DialogContent dividers>
<List dense={true}>
<ListItem>
<ListItemText primary={LL.TYPE(0)} secondary={device.tn} />
<ListItemText primary={LL.TYPE(0)} secondary={coreData.devices[deviceIndex].tn} />
</ListItem>
<ListItem>
<ListItemText primary={LL.NAME(0)} secondary={device.n} />
<ListItemText primary={LL.NAME(0)} secondary={coreData.devices[deviceIndex].n} />
</ListItem>
{device.t !== DeviceType.CUSTOM && (
{coreData.devices[deviceIndex].t !== DeviceType.CUSTOM && (
<>
<ListItem>
<ListItemText primary={LL.BRAND()} secondary={device.b} />
<ListItemText primary={LL.BRAND()} secondary={coreData.devices[deviceIndex].b} />
</ListItem>
<ListItem>
<ListItemText
primary={LL.ID_OF(LL.DEVICE())}
secondary={'0x' + ('00' + device.d.toString(16).toUpperCase()).slice(-2)}
secondary={'0x' + ('00' + coreData.devices[deviceIndex].d.toString(16).toUpperCase()).slice(-2)}
/>
</ListItem>
<ListItem>
<ListItemText primary={LL.ID_OF(LL.PRODUCT())} secondary={device.p} />
<ListItemText primary={LL.ID_OF(LL.PRODUCT())} secondary={coreData.devices[deviceIndex].p} />
</ListItem>
<ListItem>
<ListItemText primary={LL.VERSION()} secondary={device.v} />
<ListItemText primary={LL.VERSION()} secondary={coreData.devices[deviceIndex].v} />
</ListItem>
</>
)}
</List>
</DialogContent>
<DialogActions>
<Button variant="outlined" onClick={() => setDeviceDetails(-1)} color="secondary">
<Button variant="outlined" onClick={() => setShowDeviceInfo(false)} color="secondary">
{LL.CLOSE()}
</Button>
</DialogActions>
@@ -385,24 +406,16 @@ const DashboardDevices: FC = () => {
<HeaderCell stiff />
<HeaderCell stiff>{LL.TYPE(0)}</HeaderCell>
<HeaderCell resize>{LL.DESCRIPTION()}</HeaderCell>
<HeaderCell stiff>{LL.ENTITIES()}</HeaderCell>
<HeaderCell stiff />
</HeaderRow>
</Header>
<Body>
{tableList.map((device: Device, index: number) => (
{tableList.map((device: Device) => (
<Row key={device.id} item={device}>
<Cell stiff>
<DeviceIcon type_id={device.t} />
</Cell>
<Cell stiff>{device.tn}</Cell>
<Cell>{device.n}</Cell>
<Cell stiff>{device.e}</Cell>
<Cell stiff>
<IconButton size="small" onClick={() => setDeviceDetails(index)}>
<InfoOutlinedIcon color="info" sx={{ fontSize: 16, verticalAlign: 'middle' }} />
</IconButton>
</Cell>
</Row>
))}
</Body>
@@ -439,13 +452,28 @@ const DashboardDevices: FC = () => {
</>
);
const shown_data = onlyFav
? deviceData.data.filter((dv) => hasMask(dv.id, DeviceEntityMask.DV_FAVORITE))
: deviceData.data;
function truncate(str, length) {
if (str.length > length) {
return str.slice(0, length) + '...';
} else return str;
}
const deviceIndex = coreData.devices.findIndex((d) => d.id === device_select.state.id);
if (deviceIndex === -1) {
return;
}
return (
<Box
sx={{
backgroundColor: 'black',
position: 'absolute',
right: 32,
bottom: 8,
right: 16,
bottom: 16,
top: 128,
border: '1px solid #177ac9',
zIndex: 'modal'
@@ -453,45 +481,33 @@ const DashboardDevices: FC = () => {
>
<Grid container justifyContent="space-between">
<Box color="warning.main" ml={1}>
<Typography variant="h6">{deviceData.label}</Typography>
<Typography variant="h6">
{truncate(coreData.devices[deviceIndex].n, 35)}
&nbsp;({shown_data.length})
<IconButton sx={{ ml: 1 }} onClick={() => setShowDeviceInfo(true)}>
<InfoOutlinedIcon color="primary" sx={{ fontSize: 18, verticalAlign: 'middle' }} />
</IconButton>
<IconButton onClick={handleDownloadCsv}>
<DownloadIcon color="primary" sx={{ fontSize: 18, verticalAlign: 'middle' }} />
</IconButton>
<IconButton onClick={() => setOnlyFav(!onlyFav)}>
{onlyFav ? (
<StarIcon color="primary" sx={{ fontSize: 18, verticalAlign: 'middle' }} />
) : (
<StarBorderOutlinedIcon color="primary" sx={{ fontSize: 18, verticalAlign: 'middle' }} />
)}
</IconButton>
</Typography>
</Box>
<Grid item justifyContent="flex-end">
<Button
startIcon={<CancelIcon />}
size="small"
color="info"
onClick={() => device_select.fns.onRemoveAll()}
/>
<IconButton onClick={resetDeviceSelect}>
<CancelIcon color="info" sx={{ fontSize: 16, verticalAlign: 'middle' }} />
</IconButton>
</Grid>
</Grid>
<Grid item>
<FormControlLabel
control={<Checkbox size="small" name="onlyFav" checked={onlyFav} onChange={() => setOnlyFav(!onlyFav)} />}
label={
<span style={{ fontSize: '12px' }}>
{LL.SHOW_FAV()}&nbsp;(
<StarIcon color="primary" sx={{ fontSize: 12 }} />)
</span>
}
labelPlacement="start"
/>
<Button
sx={{ ml: 28 }}
startIcon={<DownloadIcon />}
size="small"
variant="outlined"
onClick={handleDownloadCsv}
>
{LL.EXPORT()}
</Button>
</Grid>
<Table
data={{
nodes: onlyFav
? deviceData.data.filter((dv) => hasMask(dv.id, DeviceEntityMask.DV_FAVORITE))
: deviceData.data
}}
data={{ nodes: shown_data }}
theme={data_theme}
sort={dv_sort}
layout={{ custom: true, fixedHeader: true }}

View File

@@ -68,7 +68,6 @@ export interface Device {
d: number; // deviceid
p: number; // productid
v: string; // version
e: number; // number of entries
}
export interface TemperatureSensor {
@@ -134,7 +133,6 @@ export interface DeviceValue {
}
export interface DeviceData {
label: string;
data: DeviceValue[];
}

View File

@@ -395,8 +395,7 @@ const emsesp_coredata = {
n: 'GBx72/Trendline/Cerapur/Greenstar Si/27i',
d: 8,
p: 123,
v: '06.01',
e: 68
v: '06.01'
},
{
id: 3,
@@ -406,8 +405,7 @@ const emsesp_coredata = {
n: 'GB125/GB135/MC10',
d: 8,
p: 123,
v: '06.01',
e: 56
v: '06.01'
},
{
id: 1,
@@ -417,8 +415,7 @@ const emsesp_coredata = {
n: 'RC35',
d: 24,
p: 86,
v: '04.01',
e: 58
v: '04.01'
},
{
id: 2,
@@ -428,8 +425,7 @@ const emsesp_coredata = {
n: 'RC20/Moduline 300',
d: 23,
p: 77,
v: '03.03',
e: 6
v: '03.03'
},
{
id: 4,
@@ -439,8 +435,7 @@ const emsesp_coredata = {
n: 'RC100/Moduline 1000/1010',
d: 16,
p: 165,
v: '04.01',
e: 3
v: '04.01'
},
{
id: 5,
@@ -450,8 +445,7 @@ const emsesp_coredata = {
n: 'MM10',
d: 32,
p: 69,
v: '01.01',
e: 6
v: '01.01'
},
{
id: 6,
@@ -461,8 +455,7 @@ const emsesp_coredata = {
n: 'SM10',
d: 48,
p: 73,
v: '01.02',
e: 16
v: '01.02'
},
{
id: 99,
@@ -472,8 +465,7 @@ const emsesp_coredata = {
n: 'User defined entities',
d: 1,
p: 1,
v: '',
e: 1
v: ''
}
]
};
@@ -526,7 +518,6 @@ const status = {
// 99 - Custom
const emsesp_devicedata_7 = {
label: 'Boiler: Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i',
data: [
{ v: '', u: 0, id: '08reset', c: 'reset', l: ['-', 'maintenance', 'error'] },
{ v: 'off', u: 0, id: '08heating active' },
@@ -607,7 +598,6 @@ const emsesp_devicedata_7 = {
};
const emsesp_devicedata_1 = {
label: 'Thermostat: RC35',
data: [
{
v: '22(816) 01.05.2023 13:07 (1 min)',
@@ -1040,7 +1030,6 @@ const emsesp_devicedata_1 = {
};
const emsesp_devicedata_2 = {
label: 'Thermostat: RC20/Moduline 300',
data: [
{
v: '(0)',
@@ -1084,7 +1073,6 @@ const emsesp_devicedata_2 = {
};
const emsesp_devicedata_3 = {
label: 'Boiler: GB125/GB135/MC10',
data: [
{
v: '',
@@ -1557,7 +1545,6 @@ const emsesp_devicedata_3 = {
};
const emsesp_devicedata_4 = {
label: 'Thermostat: RC100/Moduline 1000/1010',
data: [
{
v: 16,
@@ -1582,7 +1569,6 @@ const emsesp_devicedata_4 = {
};
const emsesp_devicedata_5 = {
label: 'Mixer Module: MM10',
data: [
{
v: 30,
@@ -1630,7 +1616,6 @@ const emsesp_devicedata_5 = {
};
const emsesp_devicedata_6 = {
label: 'Solar Module: SM10',
data: [
{
v: 43.9,
@@ -1780,7 +1765,6 @@ const emsesp_devicedata_6 = {
};
const emsesp_devicedata_99 = {
label: 'User defined entities',
data: [
{
v: 5,

View File

@@ -824,7 +824,8 @@ std::string EMSdevice::get_value_uom(const char * key) const {
// except additional data is stored in the JSON document needed for the Web UI like the UOM and command
// v=value, u=uom, n=name, c=cmd, h=help string, s=step, m=min, x=max
void EMSdevice::generate_values_web(JsonObject & output) {
output["label"] = to_string_short();
// output["label"] = to_string_short();
// output["label"] = name_;
JsonArray data = output.createNestedArray("data");
for (auto & dv : devicevalues_) {

View File

@@ -1124,6 +1124,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
emsdevices.push_back(EMSFactory::add(device_type, device_id, product_id, version, name, flags, brand));
// assign a unique ID. Note that this is not actual unique after a restart as it's dependent on the order that devices are found
// can't be 0 otherwise web won't work
emsdevices.back()->unique_id(++unique_id_count_);
// sort devices based on type

View File

@@ -88,7 +88,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
obj["d"] = emsdevice->device_id(); // deviceid
obj["p"] = emsdevice->product_id(); // productid
obj["v"] = emsdevice->version(); // version
obj["e"] = emsdevice->count_entities(); // number of entities (device values)
// obj["e"] = emsdevice->count_entities(); // number of entities (device values)
}
}
@@ -103,7 +103,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
obj["d"] = 0; // deviceid
obj["p"] = 0; // productid
obj["v"] = 0; // version
obj["e"] = EMSESP::webEntityService.count_entities(); // number of entities (device values)
// obj["e"] = EMSESP::webEntityService.count_entities(); // number of entities (device values)
}
root["connected"] = EMSESP::bus_status() != 2;