diff --git a/interface/src/project/OptionIcon.tsx b/interface/src/project/OptionIcon.tsx new file mode 100644 index 000000000..71be44969 --- /dev/null +++ b/interface/src/project/OptionIcon.tsx @@ -0,0 +1,39 @@ +import { FC } from 'react'; +import { SvgIconProps } from '@mui/material'; + +import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; +import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined'; + +import StarIcon from '@mui/icons-material/Star'; +import StarOutlineIcon from '@mui/icons-material/StarOutline'; + +import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined'; +import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; + +import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined'; +import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined'; + +type OptionType = 'readonly' | 'web_exclude' | 'api_mqtt_exclude' | 'favorite'; + +const OPTION_ICONS: { [type in OptionType]: [React.ComponentType, React.ComponentType] } = { + readonly: [EditOffOutlinedIcon, EditOutlinedIcon], + web_exclude: [VisibilityOffOutlinedIcon, VisibilityOutlinedIcon], + api_mqtt_exclude: [CommentsDisabledOutlinedIcon, InsertCommentOutlinedIcon], + favorite: [StarIcon, StarOutlineIcon] +}; + +interface OptionIconProps { + type: OptionType; + isSet: boolean; +} + +const OptionIcon: FC = ({ type, isSet }) => { + const Icon = OPTION_ICONS[type][isSet ? 0 : 1]; + return isSet ? ( + + ) : ( + + ); +}; + +export default OptionIcon; diff --git a/interface/src/project/SettingsCustomization.tsx b/interface/src/project/SettingsCustomization.tsx index d7b2d2f23..f1527a6dc 100644 --- a/interface/src/project/SettingsCustomization.tsx +++ b/interface/src/project/SettingsCustomization.tsx @@ -25,10 +25,12 @@ import { useSnackbar } from 'notistack'; import SaveIcon from '@mui/icons-material/Save'; 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 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 KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutlined'; import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined'; @@ -36,6 +38,8 @@ import UnfoldMoreOutlinedIcon from '@mui/icons-material/UnfoldMoreOutlined'; import SearchIcon from '@mui/icons-material/Search'; import FilterListIcon from '@mui/icons-material/FilterList'; +import OptionIcon from './OptionIcon'; + import { ButtonRow, FormLoader, ValidatedTextField, SectionContent } from '../components'; import * as EMSESP from './api'; @@ -202,14 +206,12 @@ const SettingsCustomization: FC = () => { function formatName(de: DeviceEntity) { if (de.n === undefined || de.n === de.id) { return de.id; + } else if (de.n === '') { + return 'Command: ' + de.id; } return de.n + ' (' + de.id + ')'; } - function isCmd(de: DeviceEntity) { - return de.n === undefined; - } - const getMaskNumber = (newMask: string[]) => { var new_mask = 0; for (let entry of newMask) { @@ -317,14 +319,14 @@ const SettingsCustomization: FC = () => { Select a device and customize each of its entities using the options: - - =mark/unmark as a favorite   - - =enable/disable write action   - - =include/exclude from MQTT and API outputs   - - =show/hide from Web Dashboard + + =mark as a favorite   + + =disable write action   + + =exclude from MQTT and API outputs   + + =hide from Web Dashboard { }} /> - - : - + + + : + + { }} > - - - + - - - + - - - + - - - + @@ -428,9 +424,9 @@ const SettingsCustomization: FC = () => { color="inherit" onClick={() => maskDisabled(false)} > - set  - - + set all  + + @@ -443,9 +439,9 @@ const SettingsCustomization: FC = () => { color="inherit" onClick={() => maskDisabled(true)} > - unset  - - + set all  + + @@ -479,23 +475,40 @@ const SettingsCustomization: FC = () => { value={getMaskString(de.m)} onChange={(event, mask) => { de.m = getMaskNumber(mask); + if (de.n === '' && de.m & DeviceEntityMask.DV_READONLY) { + de.m = de.m | DeviceEntityMask.DV_WEB_EXCLUDE; + } if (de.m & DeviceEntityMask.DV_WEB_EXCLUDE) { de.m = de.m & ~DeviceEntityMask.DV_FAVORITE; } setMasks(['']); }} > - - + + - - + + - - + + - - + + diff --git a/mock-api/server.js b/mock-api/server.js index 3acbe9f8f..0802ddcce 100644 --- a/mock-api/server.js +++ b/mock-api/server.js @@ -630,7 +630,7 @@ const emsesp_deviceentities_1 = [ ] const emsesp_deviceentities_2 = [ - { u: 0, id: 'reset', m: 8, w: false }, + { u: 0, n: '', id: 'reset', m: 8, w: false }, { v: false, n: 'heating active', id: 'heatingactive', m: 8, w: false }, { v: false, n: 'tapwater active', id: 'tapwateractive', m: 4, w: false }, { v: 5, n: 'selected flow temperature', id: 'selflowtemp', m: 4, w: true }, diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index a46ffe89f..92561391a 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -850,6 +850,8 @@ void EMSdevice::generate_values_web_customization(JsonArray & output) { obj["n"] = name; } } + } else { + obj["n"] = ""; } obj["m"] = dv.state >> 4; // send back the mask state. We're only interested in the high nibble