From 27a3bcc54e34c5e363628adb442a9c6855e507c6 Mon Sep 17 00:00:00 2001 From: Pochet Romuald Date: Thu, 20 Oct 2022 19:59:13 +0200 Subject: [PATCH 01/40] Initial commit --- .../src/assets/integrations/cover/overkiz.jpg | Bin 0 -> 33570 bytes front/src/components/app.jsx | 11 + front/src/config/i18n/en.json | 46 + front/src/config/i18n/fr.json | 46 + front/src/config/integrations/devices.json | 4 + .../all/overkiz/OverkizDeviceBox.jsx | 216 + .../integration/all/overkiz/OverkizPage.jsx | 60 + .../routes/integration/all/overkiz/actions.js | 235 + .../all/overkiz/device-page/DeviceTab.jsx | 71 + .../all/overkiz/device-page/EmptyState.jsx | 23 + .../all/overkiz/device-page/index.js | 24 + .../all/overkiz/device-page/style.css | 7 + .../all/overkiz/discover-page/DiscoverTab.jsx | 62 + .../all/overkiz/discover-page/EmptyState.jsx | 13 + .../all/overkiz/discover-page/index.js | 24 + .../all/overkiz/discover-page/style.css | 7 + .../all/overkiz/edit-page/index.js | 22 + .../all/overkiz/setup-page/SetupTab.jsx | 93 + .../all/overkiz/setup-page/index.js | 40 + server/services/index.js | 1 + .../overkiz/api/overkiz.controller.js | 66 + server/services/overkiz/index.js | 51 + .../overkiz/lib/commands/overkiz.config.js | 34 + .../overkiz/lib/commands/overkiz.connect.js | 90 + .../lib/commands/overkiz.getDevicesStates.js | 72 + .../lib/commands/overkiz.getOverkizDevices.js | 168 + .../lib/commands/overkiz.sendCommand.js | 128 + .../overkiz/lib/commands/overkiz.setValue.js | 38 + .../commands/overkiz.syncOverkizDevices.js | 65 + server/services/overkiz/lib/index.js | 39 + server/services/overkiz/lib/overkiz.util.js | 19 + .../overkiz/lib/utils/overkiz.bindValue.js | 49 + .../overkiz/lib/utils/overkiz.constants.js | 142 + .../overkiz/lib/utils/overkiz.externalId.js | 70 + server/services/overkiz/package-lock.json | 48 + server/services/overkiz/package.json | 22 + .../controllers/overkiz.controller.test.js | 85 + server/test/services/overkiz/index.test.js | 49 + .../overkiz.getOverkizDevices.test.js | 8853 +++++++++++++++++ .../services/overkiz/overkiz_devices.json | 5000 ++++++++++ 40 files changed, 16093 insertions(+) create mode 100644 front/src/assets/integrations/cover/overkiz.jpg create mode 100644 front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx create mode 100644 front/src/routes/integration/all/overkiz/OverkizPage.jsx create mode 100644 front/src/routes/integration/all/overkiz/actions.js create mode 100644 front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx create mode 100644 front/src/routes/integration/all/overkiz/device-page/EmptyState.jsx create mode 100644 front/src/routes/integration/all/overkiz/device-page/index.js create mode 100644 front/src/routes/integration/all/overkiz/device-page/style.css create mode 100644 front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx create mode 100644 front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx create mode 100644 front/src/routes/integration/all/overkiz/discover-page/index.js create mode 100644 front/src/routes/integration/all/overkiz/discover-page/style.css create mode 100644 front/src/routes/integration/all/overkiz/edit-page/index.js create mode 100644 front/src/routes/integration/all/overkiz/setup-page/SetupTab.jsx create mode 100644 front/src/routes/integration/all/overkiz/setup-page/index.js create mode 100644 server/services/overkiz/api/overkiz.controller.js create mode 100644 server/services/overkiz/index.js create mode 100644 server/services/overkiz/lib/commands/overkiz.config.js create mode 100644 server/services/overkiz/lib/commands/overkiz.connect.js create mode 100644 server/services/overkiz/lib/commands/overkiz.getDevicesStates.js create mode 100644 server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js create mode 100644 server/services/overkiz/lib/commands/overkiz.sendCommand.js create mode 100644 server/services/overkiz/lib/commands/overkiz.setValue.js create mode 100644 server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js create mode 100644 server/services/overkiz/lib/index.js create mode 100644 server/services/overkiz/lib/overkiz.util.js create mode 100644 server/services/overkiz/lib/utils/overkiz.bindValue.js create mode 100644 server/services/overkiz/lib/utils/overkiz.constants.js create mode 100644 server/services/overkiz/lib/utils/overkiz.externalId.js create mode 100644 server/services/overkiz/package-lock.json create mode 100644 server/services/overkiz/package.json create mode 100644 server/test/services/overkiz/controllers/overkiz.controller.test.js create mode 100644 server/test/services/overkiz/index.test.js create mode 100644 server/test/services/overkiz/lib/commands/overkiz.getOverkizDevices.test.js create mode 100644 server/test/services/overkiz/overkiz_devices.json diff --git a/front/src/assets/integrations/cover/overkiz.jpg b/front/src/assets/integrations/cover/overkiz.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3acdb0f4367e2140f166410e5fba8c8afe6fafa5 GIT binary patch literal 33570 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 N3((y@H2pdKKLGZif3*Mr literal 0 HcmV?d00001 diff --git a/front/src/components/app.jsx b/front/src/components/app.jsx index a771b8ecd5..d277560d1a 100644 --- a/front/src/components/app.jsx +++ b/front/src/components/app.jsx @@ -120,6 +120,12 @@ import EweLinkEditPage from '../routes/integration/all/ewelink/edit-page'; import EweLinkDiscoverPage from '../routes/integration/all/ewelink/discover-page'; import EweLinkSetupPage from '../routes/integration/all/ewelink/setup-page'; +// Overkiz +import OverkizPage from '../routes/integration/all/overkiz/device-page'; +import OverkizEditPage from '../routes/integration/all/overkiz/edit-page'; +import OverkizDiscoverPage from '../routes/integration/all/overkiz/discover-page'; +import OverkizSetupPage from '../routes/integration/all/overkiz/setup-page'; + const defaultState = getDefaultState(); const store = createStore(defaultState); @@ -236,6 +242,11 @@ const AppRouter = connect( + + + + + diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index af9a656ddb..09620fdd9c 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -1073,6 +1073,52 @@ "defaultDeletionError": "There was an error deleting the device.", "conflictError": "Current device is already in Gladys." } + }, + "overkiz": { + "title": "", + "deviceTab": "", + "discoverTab": "", + "discoverDeviceDescr": "", + "setupTab": "", + "device": { + "title": "", + "search": "", + "noDeviceFound": "", + "nameLabel": "", + "namePlaceholder": "", + "modelLabel": "", + "roomLabel": "", + "featuresLabel": "", + "alreadyCreatedButton": "", + "updateButton": "", + "saveButton": "", + "deleteButton": "", + "unmanagedModelButton": "", + "editButton": "" + }, + "status": { + "notConnected": "", + "setupPageLink": "" + }, + "discover": { + "title": "", + "scan": "", + "description": "", + "noDeviceFound": "" + }, + "setup": { + "title": "", + "overkizDescription": "", + "error": "", + "connecting": "", + "connected": "", + "connectionError": "", + "userLabel": "", + "userPlaceholder": "", + "passwordLabel": "", + "passwordPlaceholder": "", + "saveLabel": "" + } } }, "editScene": { diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index f98e02aeec..55b560db49 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -1073,6 +1073,52 @@ "defaultDeletionError": "Une erreur s'est produite lors de la suppression de l'appareil.", "conflictError": "L'appareil actuel est déjà dans Gladys." } + }, + "overkiz": { + "title": "", + "deviceTab": "", + "discoverTab": "", + "discoverDeviceDescr": "", + "setupTab": "", + "device": { + "title": "", + "search": "", + "noDeviceFound": "", + "nameLabel": "", + "namePlaceholder": "", + "modelLabel": "", + "roomLabel": "", + "featuresLabel": "", + "alreadyCreatedButton": "", + "updateButton": "", + "saveButton": "", + "deleteButton": "", + "unmanagedModelButton": "", + "editButton": "" + }, + "status": { + "notConnected": "", + "setupPageLink": "" + }, + "discover": { + "title": "", + "scan": "", + "description": "", + "noDeviceFound": "" + }, + "setup": { + "title": "", + "overkizDescription": "", + "error": "", + "connecting": "", + "connected": "", + "connectionError": "", + "userLabel": "", + "userPlaceholder": "", + "passwordLabel": "", + "passwordPlaceholder": "", + "saveLabel": "" + } } }, "editScene": { diff --git a/front/src/config/integrations/devices.json b/front/src/config/integrations/devices.json index 44244e9233..feaa477329 100644 --- a/front/src/config/integrations/devices.json +++ b/front/src/config/integrations/devices.json @@ -49,5 +49,9 @@ { "key": "broadlink", "img": "/assets/integrations/cover/broadlink.jpg" + }, + { + "key": "overkiz", + "img": "/assets/integrations/cover/overkiz.jpg" } ] diff --git a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx new file mode 100644 index 0000000000..4e3bb94331 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx @@ -0,0 +1,216 @@ +import { Component } from 'preact'; +import { Text, Localizer } from 'preact-i18n'; +import cx from 'classnames'; +import { DeviceFeatureCategoriesIcon } from '../../../../utils/consts'; +import { DEVICE_FIRMWARE, DEVICE_ONLINE } from '../../../../../../server/services/overkiz/lib/utils/overkiz.constants'; +import get from 'get-value'; +import { Link } from 'preact-router'; + +class OverkizDeviceBox extends Component { + updateName = e => { + this.props.updateDeviceField(this.props.listName, this.props.deviceIndex, 'name', e.target.value); + }; + + updateRoom = e => { + this.props.updateDeviceField(this.props.listName, this.props.deviceIndex, 'room_id', e.target.value); + }; + + saveDevice = async () => { + this.setState({ + loading: true, + errorMessage: null + }); + try { + await this.props.saveDevice(this.props.listName, this.props.deviceIndex); + } catch (e) { + let errorMessage = 'integration.overkiz.error.defaultError'; + if (e.response.status === 409) { + errorMessage = 'integration.overkiz.error.conflictError'; + } + this.setState({ + errorMessage + }); + } + this.setState({ + loading: false + }); + }; + + deleteDevice = async () => { + this.setState({ + loading: true, + errorMessage: null + }); + try { + await this.props.deleteDevice(this.props.deviceIndex); + } catch (e) { + this.setState({ + errorMessage: 'integration.overkiz.error.defaultDeletionError' + }); + } + this.setState({ + loading: false + }); + }; + + render({ deviceIndex, device, housesWithRooms, editable, ...props }, { loading, errorMessage }) { + const validModel = device.features && device.features.length > 0; + const online = device.params.find(param => param.name === DEVICE_ONLINE).value === '1'; + const firmware = device.params.find(param => param.name === DEVICE_FIRMWARE).value; + + return ( +
+
+
+ +
}> + +  {device.name} +
+
+
+ {device.params.find(param => param.name === DEVICE_FIRMWARE) && ( +
{`Firmware: ${firmware}`}
+ )} +
+
+
+
+
+
+ {errorMessage && ( +
+ +
+ )} +
+ + + } + disabled={!editable || !validModel} + /> + +
+ +
+ + +
+ + {props.updateButton && ( +
+ + +
+ )} + + {validModel && ( +
+ +
+ {device.features.map(feature => ( + + +
+ +
+
+ ))} +
+
+ )} + +
+ {validModel && props.alreadyCreatedButton && ( + + )} + + {validModel && props.updateButton && ( + + )} + + {validModel && props.saveButton && ( + + )} + + {validModel && props.deleteButton && ( + + )} + + {!validModel && ( + + )} + + {validModel && props.editButton && ( + + + + )} +
+
+
+
+
+
+ ); + } +} + +export default OverkizDeviceBox; diff --git a/front/src/routes/integration/all/overkiz/OverkizPage.jsx b/front/src/routes/integration/all/overkiz/OverkizPage.jsx new file mode 100644 index 0000000000..0b15f10847 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/OverkizPage.jsx @@ -0,0 +1,60 @@ +import { Text } from 'preact-i18n'; +import { Link } from 'preact-router/match'; + +const OverkizPage = ({ children }) => ( +
+
+
+
+
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + + +
+
+
+ +
{children}
+
+
+
+
+
+); + +export default OverkizPage; diff --git a/front/src/routes/integration/all/overkiz/actions.js b/front/src/routes/integration/all/overkiz/actions.js new file mode 100644 index 0000000000..fff3efb63e --- /dev/null +++ b/front/src/routes/integration/all/overkiz/actions.js @@ -0,0 +1,235 @@ +import update from 'immutability-helper'; +import debounce from 'debounce'; +import { RequestStatus } from '../../../../utils/consts'; +import createActionsIntegration from '../../../../actions/integration'; + +function createActions(store) { + const integrationActions = createActionsIntegration(store); + const actions = { + async loadProps(state) { + let overkizUsername; + let overkizPassword; + try { + overkizUsername = await state.httpClient.get('/api/v1/service/overkiz/variable/OVERKIZ_SERVER_USERNAME'); + overkizPassword = await state.httpClient.get('/api/v1/service/overkiz/variable/OVERKIZ_SERVER_PASSWORD'); + if (overkizPassword.value) { + overkizPassword = '*********'; // this is just used so that the field is filled + } + } finally { + store.setState({ + overkizUsername: (overkizUsername || { value: '' }).value, + overkizPassword, + passwordChanges: false, + connected: false + }); + } + }, + updateConfigration(state, e) { + const data = {}; + data[e.target.name] = e.target.value; + if (e.target.name === 'overkizPassword') { + data.passwordChanges = true; + } + store.setState(data); + }, + async saveConfiguration(state) { + event.preventDefault(); + store.setState({ + connectOverkizStatus: RequestStatus.Getting, + overkizConnected: false, + overkizConnectionError: undefined + }); + try { + await state.httpClient.post('/api/v1/service/overkiz/variable/OVERKIZ_SERVER_USERNAME', { + value: state.overkizUsername + }); + if (state.passwordChanges) { + await state.httpClient.post('/api/v1/service/overkiz/variable/OVERKIZ_SERVER_PASSWORD', { + value: state.overkizPassword + }); + } + await state.httpClient.post(`/api/v1/service/overkiz/connect`); + + store.setState({ + connectOverkizStatus: RequestStatus.Success + }); + + setTimeout(() => store.setState({ connectOverkizStatus: undefined }), 3000); + } catch (e) { + store.setState({ + connectOverkizStatus: RequestStatus.Error, + passwordChanges: false + }); + } + }, + displayConnectedMessage(state) { + // display 3 seconds a message "Overkiz connected" + store.setState({ + overkizConnected: true, + overkizConnectionError: undefined + }); + setTimeout( + () => + store.setState({ + overkizConnected: false, + connectOverkizStatus: undefined + }), + 3000 + ); + }, + displayOverkizError(state, error) { + store.setState({ + overkizConnected: false, + connectOverkizStatus: undefined, + overkizConnectionError: error + }); + }, + async getOverkizDevices(state) { + store.setState({ + getOverkizStatus: RequestStatus.Getting + }); + try { + const options = { + order_dir: state.getOverkizOrderDir || 'asc' + }; + if (state.overkizSearch && state.overkizSearch.length) { + options.search = state.overkizSearch; + } + + const overkizDevices = await state.httpClient.get('/api/v1/service/overkiz/device', options); + store.setState({ + overkizDevices, + getOverkizStatus: RequestStatus.Success + }); + } catch (e) { + store.setState({ + getOverkizStatus: e.message + }); + } + }, + async getDiscoveredOverkizDevices(state) { + store.setState({ + loading: true + }); + try { + const discoveredDevices = await state.httpClient.get('/api/v1/service/overkiz/discover'); + store.setState({ + discoveredDevices, + loading: false, + errorLoading: false + }); + } catch (e) { + store.setState({ + loading: false, + errorLoading: true + }); + } + }, + async discoverOverkizDevices(state) { + store.setState({ + loading: true + }); + try { + await state.httpClient.post('/api/v1/service/overkiz/discover'); + const discoveredDevices = await state.httpClient.get('/api/v1/service/overkiz/discover'); + store.setState({ + discoveredDevices, + loading: false, + errorLoading: false + }); + } catch (e) { + store.setState({ + loading: false, + errorLoading: true + }); + } + }, + async getHouses(state) { + store.setState({ + housesGetStatus: RequestStatus.Getting + }); + try { + const params = { + expand: 'rooms' + }; + const housesWithRooms = await state.httpClient.get(`/api/v1/house`, params); + store.setState({ + housesWithRooms, + housesGetStatus: RequestStatus.Success + }); + } catch (e) { + store.setState({ + housesGetStatus: RequestStatus.Error + }); + } + }, + updateDeviceField(state, listName, index, field, value) { + const devices = update(state[listName], { + [index]: { + [field]: { + $set: value + } + } + }); + store.setState({ + [listName]: devices + }); + }, + updateFeatureProperty(state, listName, deviceIndex, featureIndex, property, value) { + const devices = update(state[listName], { + [deviceIndex]: { + features: { + [featureIndex]: { + [property]: { + $set: value + } + } + } + } + }); + + store.setState({ + [listName]: devices + }); + }, + async saveDevice(state, listName, index) { + const device = state[listName][index]; + const savedDevice = await state.httpClient.post(`/api/v1/device`, device); + const devices = update(state[listName], { + $splice: [[index, 1, savedDevice]] + }); + store.setState({ + [listName]: devices + }); + }, + async deleteDevice(state, index) { + const device = state.overkizDevices[index]; + if (device.created_at) { + await state.httpClient.delete(`/api/v1/device/${device.selector}`); + } + const overkizDevices = update(state.overkizDevices, { + $splice: [[index, 1]] + }); + store.setState({ + overkizDevices + }); + }, + async search(state, e) { + store.setState({ + overkizSearch: e.target.value + }); + await actions.getOverkizDevices(store.getState()); + }, + async changeOrderDir(state, e) { + store.setState({ + getOverkizOrderDir: e.target.value + }); + await actions.getOverkizDevices(store.getState()); + } + }; + actions.debouncedSearch = debounce(actions.search, 200); + + return Object.assign({}, integrationActions, actions); +} + +export default createActions; diff --git a/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx b/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx new file mode 100644 index 0000000000..c80be6d3dc --- /dev/null +++ b/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx @@ -0,0 +1,71 @@ +import { Text, Localizer } from 'preact-i18n'; +import cx from 'classnames'; + +import EmptyState from './EmptyState'; +import { RequestStatus } from '../../../../../utils/consts'; +import style from './style.css'; +import OverkizDeviceBox from '../OverkizDeviceBox'; + +const DeviceTab = ({ children, ...props }) => ( +
+
+

+ +

+
+ +
+ + + + + } + onInput={props.debouncedSearch} + /> + +
+
+
+
+
+
+
+
+ {props.overkizDevices && + props.overkizDevices.length > 0 && + props.overkizDevices.map((device, index) => ( + + ))} + {!props.overkizDevices || (props.overkizDevices.length === 0 && )} +
+
+
+
+
+); + +export default DeviceTab; diff --git a/front/src/routes/integration/all/overkiz/device-page/EmptyState.jsx b/front/src/routes/integration/all/overkiz/device-page/EmptyState.jsx new file mode 100644 index 0000000000..f0e20e98f9 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/device-page/EmptyState.jsx @@ -0,0 +1,23 @@ +import { Text } from 'preact-i18n'; +import { Link } from 'preact-router/match'; +import cx from 'classnames'; +import style from './style.css'; + +const EmptyState = () => ( +
+
+ + +
+ + + + +
+
+
+); + +export default EmptyState; diff --git a/front/src/routes/integration/all/overkiz/device-page/index.js b/front/src/routes/integration/all/overkiz/device-page/index.js new file mode 100644 index 0000000000..b13f2f4b18 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/device-page/index.js @@ -0,0 +1,24 @@ +import { Component } from 'preact'; +import { connect } from 'unistore/preact'; +import actions from '../actions'; +import OverkizPage from '../OverkizPage'; +import DeviceTab from './DeviceTab'; + +@connect('user,overkizDevices,housesWithRooms,getOverkizStatus', actions) +class OverkizIntegration extends Component { + componentWillMount() { + this.props.getOverkizDevices(); + this.props.getHouses(); + this.props.getIntegrationByName('overkiz'); + } + + render(props, {}) { + return ( + + + + ); + } +} + +export default OverkizIntegration; diff --git a/front/src/routes/integration/all/overkiz/device-page/style.css b/front/src/routes/integration/all/overkiz/device-page/style.css new file mode 100644 index 0000000000..d4efd465ce --- /dev/null +++ b/front/src/routes/integration/all/overkiz/device-page/style.css @@ -0,0 +1,7 @@ +.emptyStateDivBox { + margin-top: 35px; +} + +.overkizListBody { + min-height: 200px +} diff --git a/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx b/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx new file mode 100644 index 0000000000..a675e97422 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx @@ -0,0 +1,62 @@ +import { Text } from 'preact-i18n'; +import { Link } from 'preact-router/match'; +import cx from 'classnames'; + +import EmptyState from './EmptyState'; +import style from './style.css'; +import OverkizDeviceBox from '../OverkizDeviceBox'; + +const DeviceTab = ({ children, ...props }) => ( +
+
+

+ +

+
+ +
+
+
+
+ +
+
+
+
+ {props.errorLoading && ( +

+ + + + +

+ )} +
+ {props.discoveredDevices && + props.discoveredDevices.map((device, index) => ( + + ))} + {!props.discoveredDevices || (props.discoveredDevices.length === 0 && )} +
+
+
+
+
+); + +export default DeviceTab; diff --git a/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx b/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx new file mode 100644 index 0000000000..25b7a257aa --- /dev/null +++ b/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx @@ -0,0 +1,13 @@ +import { MarkupText } from 'preact-i18n'; +import cx from 'classnames'; +import style from './style.css'; + +const EmptyState = ({ children }) => ( +
+
+ +
+
+); + +export default EmptyState; diff --git a/front/src/routes/integration/all/overkiz/discover-page/index.js b/front/src/routes/integration/all/overkiz/discover-page/index.js new file mode 100644 index 0000000000..4f8dbddb8e --- /dev/null +++ b/front/src/routes/integration/all/overkiz/discover-page/index.js @@ -0,0 +1,24 @@ +import { Component } from 'preact'; +import { connect } from 'unistore/preact'; +import actions from '../actions'; +import OverkizPage from '../OverkizPage'; +import DiscoverTab from './DiscoverTab'; + +@connect('user,session,httpClient,housesWithRooms,discoveredDevices,loading,errorLoading', actions) +class OverkizIntegration extends Component { + async componentWillMount() { + this.props.getDiscoveredOverkizDevices(); + this.props.getHouses(); + this.props.getIntegrationByName('overkiz'); + } + + render(props) { + return ( + + + + ); + } +} + +export default OverkizIntegration; diff --git a/front/src/routes/integration/all/overkiz/discover-page/style.css b/front/src/routes/integration/all/overkiz/discover-page/style.css new file mode 100644 index 0000000000..1e79fa56d5 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/discover-page/style.css @@ -0,0 +1,7 @@ +.emptyStateDivBox { + margin-top: 89px; +} + +.overkizListBody { + min-height: 200px; +} diff --git a/front/src/routes/integration/all/overkiz/edit-page/index.js b/front/src/routes/integration/all/overkiz/edit-page/index.js new file mode 100644 index 0000000000..13fff479f7 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/edit-page/index.js @@ -0,0 +1,22 @@ +import { Component } from 'preact'; +import { connect } from 'unistore/preact'; +import OverkizPage from '../OverkizPage'; +import UpdateDevice from '../../../../../components/device'; + +@connect('user,session,httpClient,currentIntegration,houses', {}) +class EditOverkizDevice extends Component { + render(props, {}) { + return ( + + + + ); + } +} + +export default EditOverkizDevice; diff --git a/front/src/routes/integration/all/overkiz/setup-page/SetupTab.jsx b/front/src/routes/integration/all/overkiz/setup-page/SetupTab.jsx new file mode 100644 index 0000000000..979d08384a --- /dev/null +++ b/front/src/routes/integration/all/overkiz/setup-page/SetupTab.jsx @@ -0,0 +1,93 @@ +import { Text, Localizer } from 'preact-i18n'; +import cx from 'classnames'; + +import { RequestStatus } from '../../../../../utils/consts'; + +const SetupTab = ({ children, ...props }) => { + return ( +
+
+

+ +

+
+
+
+
+
+

+ +

+ {props.connectOverkizStatus === RequestStatus.Error && !props.overkizConnectionError && ( +

+ +

+ )} + {props.connectOverkizStatus === RequestStatus.Success && !props.overkizConnected && ( +

+ +

+ )} + {props.overkizConnected && ( +

+ +

+ )} + {props.overkizConnectionError && ( +

+ +

+ )} + +
+
+ + + } + value={props.overkizUsername} + class="form-control" + onInput={props.updateConfigration} + /> + +
+ +
+ + + } + value={props.overkizPassword} + class="form-control" + onInput={props.updateConfigration} + /> + +
+ +
+
+ +
+
+
+
+
+
+
+ ); +}; + +export default SetupTab; diff --git a/front/src/routes/integration/all/overkiz/setup-page/index.js b/front/src/routes/integration/all/overkiz/setup-page/index.js new file mode 100644 index 0000000000..51d14a29a2 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/setup-page/index.js @@ -0,0 +1,40 @@ +import { Component } from 'preact'; +import { connect } from 'unistore/preact'; +import actions from '../actions'; +import OverkizPage from '../OverkizPage'; +import SetupTab from './SetupTab'; +import { WEBSOCKET_MESSAGE_TYPES } from '../../../../../../../server/utils/constants'; + +@connect( + 'user,session,overkizUsername,overkizPassword,connectOverkizStatus,overkizConnected,overkizConnectionError', + actions +) +class OverkizSetupPage extends Component { + componentWillMount() { + this.props.getIntegrationByName('overkiz'); + this.props.loadProps(); + this.props.session.dispatcher.addListener( + WEBSOCKET_MESSAGE_TYPES.OVERKIZ.CONNECTED, + this.props.displayConnectedMessage + ); + this.props.session.dispatcher.addListener(WEBSOCKET_MESSAGE_TYPES.OVERKIZ.ERROR, this.props.displayOverkizError); + } + + componentWillUnmount() { + this.props.session.dispatcher.removeListener( + WEBSOCKET_MESSAGE_TYPES.OVERKIZ.CONNECTED, + this.props.displayConnectedMessage + ); + this.props.session.dispatcher.removeListener(WEBSOCKET_MESSAGE_TYPES.OVERKIZ.ERROR, this.props.displayOverkizError); + } + + render(props, {}) { + return ( + + + + ); + } +} + +export default OverkizSetupPage; diff --git a/server/services/index.js b/server/services/index.js index 53f4b66b4e..4c94caae3e 100644 --- a/server/services/index.js +++ b/server/services/index.js @@ -16,3 +16,4 @@ module.exports['tp-link'] = require('./tp-link'); module.exports.zigbee2mqtt = require('./zigbee2mqtt'); module.exports['google-actions'] = require('./google-actions'); module.exports.broadlink = require('./broadlink'); +module.exports.overkiz = require('./overkiz'); \ No newline at end of file diff --git a/server/services/overkiz/api/overkiz.controller.js b/server/services/overkiz/api/overkiz.controller.js new file mode 100644 index 0000000000..425995d761 --- /dev/null +++ b/server/services/overkiz/api/overkiz.controller.js @@ -0,0 +1,66 @@ +const asyncMiddleware = require('../../../api/middlewares/asyncMiddleware'); + +module.exports = function OverkizController(overkizHandler) { + /** + * @api {post} /api/v1/service/overkiz/connect Connect to overkiz cloud account. + * @apiName save + * @apiGroup overkiz + */ + async function connect(req, res) { + await overkizHandler.connect(); + res.json({ + success: true, + }); + } + + /** + * @api {get} /api/v1/service/overkiz/status Get overkiz connection status. + * @apiName status + * @apiGroup overkiz + */ + async function status(req, res) { + const response = overkizHandler.status(); + res.json(response); + } + + /** + * @api {get} /api/v1/service/overkiz/discover Retrieve overkiz devices from cloud. + * @apiName discover + * @apiGroup overkiz + */ + async function getDevices(req, res) { + const devices = await overkizHandler.getOverkizDevices(); + res.json(devices); + } + + /** + * @api {post} /api/v1/service/overkiz/discover Scan for overkiz devices from cloud. + * @apiName discover + * @apiGroup overkiz + */ + async function discoverDevices(req, res) { + await overkizHandler.syncOverkizDevices(); + const devices = await overkizHandler.getOverkizDevices(); + res.json(devices); + } + + return { + 'post /api/v1/service/overkiz/connect': { + authenticated: true, + admin: true, + controller: asyncMiddleware(connect), + }, + 'get /api/v1/service/overkiz/status': { + authenticated: true, + controller: status, + }, + 'get /api/v1/service/overkiz/discover': { + authenticated: true, + controller: asyncMiddleware(getDevices), + }, + 'post /api/v1/service/overkiz/discover': { + authenticated: true, + controller: asyncMiddleware(discoverDevices), + }, + }; +}; diff --git a/server/services/overkiz/index.js b/server/services/overkiz/index.js new file mode 100644 index 0000000000..610b575fb3 --- /dev/null +++ b/server/services/overkiz/index.js @@ -0,0 +1,51 @@ +const logger = require('../../utils/logger'); +const OverkizHandler = require('./lib'); +const OverkizController = require('./api/overkiz.controller'); +const { ServiceNotConfiguredError } = require('../../utils/coreErrors'); +const { OVERKIZ_SERVER_PARAM } = require('./lib/utils/overkiz.constants'); + +module.exports = function OverkizService(gladys, serviceId) { + const overkizHandler = new OverkizHandler(gladys, serviceId); + + /** + * @public + * @description This function starts the Overkiz service + * @example + * gladys.services.overkiz.start(); + */ + async function start() { + logger.info('Starting Overkiz service'); + + await gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE, 'atlantic_cozytouch', serviceId); + await gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_USERNAME, 'pochet.romuald@gmail.com', serviceId); + await gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_PASSWORD, '8Vyr7acpcozytouch', serviceId); + + // Authorization server + const overkizType = await gladys.variable.getValue(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE, serviceId); + if (!overkizType) { + throw new ServiceNotConfiguredError(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE); + } + overkizHandler.overkizType = overkizType; + + await overkizHandler.connect(); + + overkizHandler.syncOverkizDevices(); + } + + /** + * @public + * @description This function stops the Overkiz service + * @example + * gladys.services.overkiz.stop(); + */ + async function stop() { + logger.info('Stopping Overkiz service'); + } + + return Object.freeze({ + start, + stop, + device: overkizHandler, + controllers: OverkizController(overkizHandler), + }); +}; diff --git a/server/services/overkiz/lib/commands/overkiz.config.js b/server/services/overkiz/lib/commands/overkiz.config.js new file mode 100644 index 0000000000..e838377259 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.config.js @@ -0,0 +1,34 @@ +const logger = require('../../../../utils/logger'); + +/** + * @description Overkiz config + * @example + * overkiz.config(); + */ +function config() { + logger.debug(`Overkiz : Config`); +} + +/** + * @description Enable Discovery + * @example + * overkiz.enableDiscovery(); + */ +function enableDiscovery() { + logger.debug(`Overkiz : Enable discovery`); +} + +/** + * @description Disable Discovery + * @example + * overkiz.disableDiscovery(); + */ +function disableDiscovery() { + logger.debug(`Overkiz : Disable discovery`); +} + +module.exports = { + config, + enableDiscovery, + disableDiscovery, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.connect.js b/server/services/overkiz/lib/commands/overkiz.connect.js new file mode 100644 index 0000000000..b1492fe2fb --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.connect.js @@ -0,0 +1,90 @@ +const axios = require('axios'); +const url = require('url'); +const { WEBSOCKET_MESSAGE_TYPES, EVENTS } = require('../../../../utils/constants'); +const { ServiceNotConfiguredError } = require('../../../../utils/coreErrors'); +const logger = require('../../../../utils/logger'); +const { OVERKIZ_SERVER_PARAM, SUPPORTED_SERVERS } = require('../utils/overkiz.constants'); + +/** + * @description Connect to OverKiz server. + * @returns {Promise} Return Object of informations. + * @example + * overkiz.connect(); + */ +async function connect() { + logger.info(`Overkiz : Connecting server...`); + + const overkizType = await this.gladys.variable.getValue(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE, this.serviceId); + if (!overkizType) { + throw new ServiceNotConfiguredError(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE); + } + + const overkizUsername = await this.gladys.variable.getValue( + OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_USERNAME, + this.serviceId, + ); + if (!overkizUsername) { + throw new ServiceNotConfiguredError(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_USERNAME); + } + + const overkizUserpassword = await this.gladys.variable.getValue( + OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_PASSWORD, + this.serviceId, + ); + if (!overkizUserpassword) { + throw new ServiceNotConfiguredError(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_PASSWORD); + } + + this.overkizServer = SUPPORTED_SERVERS[overkizType]; + + let payload; + if (this.overkizServer.jwt) { + const params = new url.URLSearchParams({ + username: overkizUsername, + password: overkizUserpassword, + grant_type: 'password', + }); + let response = await axios + .post(`${this.overkizServer.configuration.COZYTOUCH_ATLANTIC_API}/token`, params, { + headers: { + Authorization: `Basic ${this.overkizServer.configuration.COZYTOUCH_CLIENT_ID}`, + }, + }) + .catch((error) => logger.error(error)); + logger.debug(`access_token: ${response.data.access_token}`); + + response = await axios.get( + `${this.overkizServer.configuration.COZYTOUCH_ATLANTIC_API}/gacoma/gacomawcfservice/accounts/jwt`, + { + headers: { + Authorization: `Bearer ${response.data.access_token}`, + }, + }, + ); + logger.debug(`JWT: ${response.data}`); + payload = { + jwt: response.data, + }; + } else { + payload = { + userId: overkizUsername, + userPassword: overkizUserpassword, + }; + } + + const response = await axios.post(`${this.overkizServer.endpoint}/login`, new url.URLSearchParams(payload)); + + logger.info(`Overkiz : Server connection OK`); + const cookie = response.headers['set-cookie'][0]; + this.sessionCookie = cookie.substring(cookie.indexOf('=') + 1, cookie.indexOf(';')); + this.connected = true; + + this.eventManager.emit(EVENTS.WEBSOCKET.SEND_ALL, { + type: WEBSOCKET_MESSAGE_TYPES.OVERKIZ.CONNECTED, + payload: {}, + }); +} + +module.exports = { + connect, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js new file mode 100644 index 0000000000..0120cdeec4 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js @@ -0,0 +1,72 @@ +const axios = require('axios'); +const retry = require('async-retry'); +const logger = require('../../../../utils/logger'); +const { getDeviceFeatureExternalId, getNodeStateInfoByExternalId } = require('../utils/overkiz.externalId'); +const { unbindValue } = require('../utils/overkiz.bindValue'); +const { connect } = require('./overkiz.connect'); +const { EVENTS } = require('../../../../utils/constants'); + +/** + * @description Update device states. + * @param {Object} device - Deviceto update states. + * @returns {Promise} Return Object of informations. + * @example + * overkiz.getDevicesStates(); + */ +async function getDevicesStates(device) { + logger.info(`Overkiz : Get device state...`); + + device.features.map(async (feature) => { + const { deviceURL } = getNodeStateInfoByExternalId(feature); + + const response = await retry( + async (bail) => { + const tryResponse = await axios.get( + `${this.overkizServer.endpoint}setup/devices/${encodeURIComponent(deviceURL)}/states`, + { + headers: { + 'Cache-Control': 'no-cache', + Host: this.overkizServer.endpoint.substring( + this.overkizServer.endpoint.indexOf('/') + 2, + this.overkizServer.endpoint.indexOf('/', 8), + ), + Connection: 'Keep-Alive', + Cookie: `JSESSIONID=${this.sessionCookie}`, + }, + }, + ); + return tryResponse; + }, + { + retries: 5, + onRetry: (err, num) => { + if (err.response && err.response.status === 401) { + connect.bind(this)(); + logger.info(`Overkiz : Connecting Overkiz server...`); + } else { + throw err; + } + }, + }, + ); + + device.states = response.data; + logger.info(`Overkiz : Get new device states: ${deviceURL}`); + + device.states.forEach((state) => { + const deviceFeatureExternalId = getDeviceFeatureExternalId({ deviceURL }, state.name); + const newValueUnbind = unbindValue(device, state.name, state.value); + const deviceFeature = this.gladys.stateManager.get('deviceFeatureByExternalId', deviceFeatureExternalId); + if (deviceFeature) { + this.eventManager.emit(EVENTS.DEVICE.NEW_STATE, { + device_feature_external_id: deviceFeatureExternalId, + state: newValueUnbind, + }); + } + }); + }); +} + +module.exports = { + getDevicesStates, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js new file mode 100644 index 0000000000..422d980fe4 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js @@ -0,0 +1,168 @@ +const { + DEVICE_FEATURE_CATEGORIES, + DEVICE_FEATURE_UNITS, + DEVICE_FEATURE_TYPES, + DEVICE_POLL_FREQUENCIES, +} = require('../../../../utils/constants'); +const { + DEVICE_ONLINE, + DEVICE_FIRMWARE, + DEVICE_UID_CLASSES, + DEVICE_STATES, + DEVICE_TYPES, + HEATING_LEVELS, +} = require('../utils/overkiz.constants'); +const { getDeviceName, getDeviceFeatureExternalId, getDeviceExternalId } = require('../utils/overkiz.externalId'); + +/** + * @description Return array of Devices. + * @returns {Promise} Return list of devices. + * @example + * const devices = overkizHandler.getDevices(); + */ +async function getOverkizDevices() { + const deviceOids = Object.keys(this.devices); + + const newDevices = deviceOids + .map((deviceOid) => Object.assign({}, { id: deviceOid }, this.devices[deviceOid])) + .filter((node) => node.type === DEVICE_TYPES.SYSTEM) + .filter((node) => node.uiClass !== DEVICE_UID_CLASSES.POD) + .map((node) => { + const states = node.states.reduce((map, obj) => { + map[obj.name] = obj.value; + return map; + }, {}); + + const attributes = node.attributes.reduce((map, obj) => { + map[obj.name] = obj.value; + return map; + }, {}); + + const newDevice = { + name: getDeviceName(node), + model: `${states[DEVICE_STATES.MODEL_STATE]} ${states[DEVICE_STATES.POWER_STATE]}W (${ + states[DEVICE_STATES.MANUFACTURER_NAME_STATE] + })`, + service_id: this.serviceId, + external_id: getDeviceExternalId(node), + updatable: true, + ready: node.available && node.enabled, + rawOverkizDevice: node, + should_poll: true, + poll_frequency: DEVICE_POLL_FREQUENCIES.EVERY_10_MINUTES, + features: [], + params: [ + { + name: DEVICE_ONLINE, + value: states[DEVICE_STATES.STATUS_STATE], + }, + { + name: DEVICE_FIRMWARE, + value: attributes[DEVICE_STATES.FIRMWARE_REVISION_STATE], + }, + ], + }; + + return newDevice; + }) + .reduce((map, obj) => { + // Remove # to get all nodes from the same physical device + map[obj.rawOverkizDevice.deviceURL.slice(0, -2)] = obj; + return map; + }, {}); + // foreach node in RAM, we format it with the gladys device format + deviceOids + .map((deviceOid) => Object.assign({}, { id: deviceOid }, this.devices[deviceOid])) + .filter((node) => newDevices[node.deviceURL.slice(0, -2)] !== undefined) + .map((node) => { + const newDevice = newDevices[node.deviceURL.slice(0, -2)]; + const newFeature = { + rawOverkizDevice: node, + }; + if (node.uiClass === DEVICE_UID_CLASSES.HEATER) { + newDevice.features.push( + Object.assign({}, newFeature, { + name: `Mode`, + selector: `overkiz-${node.deviceURL}-${node.uiClass}-${DEVICE_STATES.HEATING_LEVEL_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.HEATING_LEVEL_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.HEATER.LEVEL, + read_only: false, + has_feedback: true, + min: 0, + max: HEATING_LEVELS.length - 1, + }), + ); + newDevice.features.push( + Object.assign({}, newFeature, { + name: `Comfort mode temperature`, + selector: `overkiz-${node.deviceURL}-${node.uiClass}-${DEVICE_STATES.COMFORT_TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.COMFORT_TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, + read_only: false, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }), + ); + newDevice.features.push( + Object.assign({}, newFeature, { + name: `Eco mode temperature`, + selector: `overkiz-${node.deviceURL}-${node.uiClass}-${DEVICE_STATES.ECO_TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.ECO_TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, + read_only: false, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }), + ); + } else if (node.uiClass === DEVICE_UID_CLASSES.TEMPERATURE) { + newDevice.features.push( + Object.assign({}, newFeature, { + name: `Temperature`, + selector: `overkiz-${node.deviceURL}-${node.uiClass}-${DEVICE_STATES.TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR, + type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL, + read_only: true, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }), + ); + } else if (node.uiClass === DEVICE_UID_CLASSES.OCCUPANCY) { + newDevice.features.push( + Object.assign({}, newFeature, { + name: `Occupancy`, + selector: `overkiz-${node.deviceURL}-${node.uiClass}-${DEVICE_STATES.OCCUPANCY_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.OCCUPANCY_STATE), + category: DEVICE_FEATURE_CATEGORIES.PRESENCE_SENSOR, + type: DEVICE_FEATURE_TYPES.SENSOR.PUSH, + min: 0, + max: 1, + read_only: true, + has_feedback: false, + keep_history: true, + }), + ); + } + return newDevice; + }); + + const newDevicesOids = Object.keys(newDevices); + return newDevicesOids + .map((newDevicesOid) => Object.assign({}, newDevices[newDevicesOid])) + .sort(function sortByNodeReady(a, b) { + return b.ready - a.ready || a.rawOverkizDevice.id - b.rawOverkizDevice.id; + }); +} + +module.exports = { + getOverkizDevices, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.sendCommand.js b/server/services/overkiz/lib/commands/overkiz.sendCommand.js new file mode 100644 index 0000000000..bdb69e8f6e --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.sendCommand.js @@ -0,0 +1,128 @@ +const axios = require('axios'); +const retry = require('async-retry'); +const sleep = require('sleep-promise'); +const logger = require('../../../../utils/logger'); + +const { connect } = require('./overkiz.connect'); + +/** + * @description Connect to OverKiz server. + * @param {string} execId - Execution Id. + * @returns {Promise} Return state of Execution. + * @example + * overkiz.getExecutionState('01234'); + */ +async function getExecutionState(execId) { + const response = await retry( + async (bail) => { + const tryResponse = await axios.get(`${this.overkizServer.endpoint}exec/current/${execId}`, { + headers: { + 'Cache-Control': 'no-cache', + Host: this.overkizServer.endpoint.substring( + this.overkizServer.endpoint.indexOf('/') + 2, + this.overkizServer.endpoint.indexOf('/', 8), + ), + Connection: 'Keep-Alive', + Cookie: `JSESSIONID=${this.sessionCookie}`, + }, + }); + return tryResponse; + }, + { + retries: 5, + onRetry: (err, num) => { + if (err.response && err.response.status === 401) { + connect.bind(this)(); + logger.info(`Overkiz : Connecting Overkiz server...`); + } else { + throw err; + } + }, + }, + ); + + return response; +} + +/** + * @description Connect to OverKiz server. + * @param {Object} command - Command to send. + * @param {string} deviceURL - DeviceURL. + * @param {Object} data - Command data to send. + * @returns {Promise} Return Object of informations. + * @example + * overkiz.sendCommand(); + */ +async function sendCommand(command, deviceURL, data) { + logger.info(`Overkiz : Sending command...`); + + const payload = { + label: `${command} to device ${deviceURL}`, + actions: [ + { + deviceURL, + commands: [ + { + name: command, + parameters: [data], + }, + ], + }, + ], + }; + const response = await retry( + async (bail) => { + const tryResponse = await axios.post(`${this.overkizServer.endpoint}exec/apply`, payload, { + headers: { + 'Cache-Control': 'no-cache', + Host: this.overkizServer.endpoint.substring( + this.overkizServer.endpoint.indexOf('/') + 2, + this.overkizServer.endpoint.indexOf('/', 8), + ), + Connection: 'Keep-Alive', + Cookie: `JSESSIONID=${this.sessionCookie}`, + }, + }); + return tryResponse; + }, + { + retries: 5, + onRetry: (err, num) => { + if (err.response && err.response.status === 401) { + connect.bind(this)(); + logger.info(`Overkiz : Connecting Overkiz server...`); + } else { + throw err; + } + }, + }, + ); + + logger.info(`Overkiz : Command sent - Exec Id: ${response.data.execId}`); + + const { execId } = response.data; + + let execResponse = await getExecutionState.bind(this)(execId); + const { state1 } = execResponse.data; + logger.debug(state1); + await sleep(500); // Wait 2000 ms + + execResponse = await getExecutionState.bind(this)(execId); + const { state2 } = execResponse.data; + logger.debug(state2); + await sleep(500); // Wait 2000 ms + + execResponse = await getExecutionState.bind(this)(execId); + const { state3 } = execResponse.data; + logger.debug(state3); + await sleep(500); // Wait 2000 ms + + execResponse = await getExecutionState.bind(this)(execId); + const { state4 } = execResponse.data; + await sleep(500); // Wait 2000 ms + logger.debug(state4); +} + +module.exports = { + sendCommand, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.setValue.js b/server/services/overkiz/lib/commands/overkiz.setValue.js new file mode 100644 index 0000000000..3953a2bbe9 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.setValue.js @@ -0,0 +1,38 @@ +const logger = require('../../../../utils/logger'); +const { bindValue } = require('../utils/overkiz.bindValue'); +const { DEVICE_COMMANDS, DEVICE_STATES } = require('../utils/overkiz.constants'); +const { getNodeStateInfoByExternalId } = require('../utils/overkiz.externalId'); +const { sendCommand } = require('./overkiz.sendCommand'); + +/** + * @description Connect to OverKiz server. + * @param {Object} device - Device to set feature value. + * @param {Object} deviceFeature - Device feature to set value. + * @param {Object} value - Value to set. + * @example + * overkiz.setValue(); + */ +async function setValue(device, deviceFeature, value) { + const { deviceURL, state } = getNodeStateInfoByExternalId(deviceFeature); + const overkizValue = bindValue(device, deviceFeature, value); + + logger.info(`Setting value ${value} -> ${overkizValue} for device feature ${deviceFeature.external_id}`); + + switch (state) { + case DEVICE_STATES.HEATING_LEVEL_STATE: + sendCommand.bind(this)(DEVICE_COMMANDS.SET_HEATING_LEVEL, deviceURL, overkizValue); + break; + case DEVICE_STATES.COMFORT_TEMPERATURE_STATE: + sendCommand.bind(this)(DEVICE_COMMANDS.SET_COMFORT_TEMP, deviceURL, overkizValue); + break; + case DEVICE_STATES.ECO_TEMPERATURE_STATE: + sendCommand.bind(this)(DEVICE_COMMANDS.SET_ECO_TEMP, deviceURL, overkizValue); + break; + default: + // + } +} + +module.exports = { + setValue, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js new file mode 100644 index 0000000000..710eeae748 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js @@ -0,0 +1,65 @@ +const axios = require('axios'); +const retry = require('async-retry'); +const logger = require('../../../../utils/logger'); + +const { updateGatewayState } = require('../overkiz.util'); +const { connect } = require('./overkiz.connect'); +const { ServiceNotConfiguredError } = require('../../../../utils/coreErrors'); + +/** + * @description Synchronize Overkiz devices. + * @returns {Promise} Overkiz devices. + * @example + * overkiz.syncOverkizDevices(); + */ +async function syncOverkizDevices() { + if (!this.connected) { + throw new ServiceNotConfiguredError('OVERKIZ_NOT_CONNECTED'); + } + logger.debug(`Overkiz : Starting discovery`); + + const response = await retry( + async (bail) => { + const tryResponse = await axios.get(`${this.overkizServer.endpoint}setup`, { + headers: { + 'Cache-Control': 'no-cache', + Host: this.overkizServer.endpoint.substring( + this.overkizServer.endpoint.indexOf('/') + 2, + this.overkizServer.endpoint.indexOf('/', 8), + ), + Connection: 'Keep-Alive', + Cookie: `JSESSIONID=${this.sessionCookie}`, + }, + }); + return tryResponse; + }, + { + retries: 5, + onRetry: (err, num) => { + if (err.response && err.response.status === 401) { + connect.bind(this)(); + logger.info(`Overkiz : Connecting Overkiz server...`); + } else { + throw err; + } + }, + }, + ); + + this.devices = {}; + response.data.devices.forEach((device) => { + const placeObj = response.data.rootPlace.subPlaces.find((place) => place.oid === device.placeOID); + if (placeObj) { + device.place = placeObj.label; + } + this.devices[device.oid] = device; + }); + + updateGatewayState(response.data.gateways); + + return this.devices; +} + +module.exports = { + syncOverkizDevices, +}; diff --git a/server/services/overkiz/lib/index.js b/server/services/overkiz/lib/index.js new file mode 100644 index 0000000000..4e5735af95 --- /dev/null +++ b/server/services/overkiz/lib/index.js @@ -0,0 +1,39 @@ +const Bottleneck = require('bottleneck/es5'); + +const { enableDiscovery, disableDiscovery, config } = require('./commands/overkiz.config'); +const { connect } = require('./commands/overkiz.connect'); +const { getDevicesStates } = require('./commands/overkiz.getDevicesStates'); +const { getOverkizDevices } = require('./commands/overkiz.getOverkizDevices'); +const { setValue } = require('./commands/overkiz.setValue'); +const { syncOverkizDevices } = require('./commands/overkiz.syncOverkizDevices'); + +// we rate-limit the number of request per seconds to poll lights +const pollLimiter = new Bottleneck({ + maxConcurrent: 1, + minTime: 100, // 100 ms +}); + +// we rate-limit the number of request per seconds to control lights +const setValueLimiter = new Bottleneck({ + minTime: 100, // 100 ms +}); + +const OverkizHandler = function OverkizHandler(gladys, serviceId) { + this.gladys = gladys; + this.serviceId = serviceId; + this.eventManager = gladys.event; + this.devices = {}; + this.connected = false; + this.scanInProgress = false; +}; + +OverkizHandler.prototype.connect = connect; +OverkizHandler.prototype.syncOverkizDevices = syncOverkizDevices; +OverkizHandler.prototype.getOverkizDevices = getOverkizDevices; +OverkizHandler.prototype.poll = pollLimiter.wrap(getDevicesStates); +OverkizHandler.prototype.setValue = setValueLimiter.wrap(setValue); +OverkizHandler.prototype.enableDiscovery = enableDiscovery; +OverkizHandler.prototype.disableDiscovery = disableDiscovery; +OverkizHandler.prototype.config = config; + +module.exports = OverkizHandler; diff --git a/server/services/overkiz/lib/overkiz.util.js b/server/services/overkiz/lib/overkiz.util.js new file mode 100644 index 0000000000..cd1ec2458f --- /dev/null +++ b/server/services/overkiz/lib/overkiz.util.js @@ -0,0 +1,19 @@ +const logger = require('../../../utils/logger'); + +/** + * @description Update Gatway State. + * @param {Object} gateways - List of gateways. + * @example + * overkiz.updateGatewayState(); + */ +function updateGatewayState(gateways) { + logger.debug('UpdateGatwayState'); + + this.gateways = gateways; + + // TODO send event +} + +module.exports = { + updateGatewayState, +}; diff --git a/server/services/overkiz/lib/utils/overkiz.bindValue.js b/server/services/overkiz/lib/utils/overkiz.bindValue.js new file mode 100644 index 0000000000..9987ac0c9f --- /dev/null +++ b/server/services/overkiz/lib/utils/overkiz.bindValue.js @@ -0,0 +1,49 @@ +const { DEVICE_STATES, HEATING_LEVELS } = require('./overkiz.constants'); +const { getNodeStateInfoByExternalId } = require('./overkiz.externalId'); + +/** + * @description Bind value + * @param {Object} device - Device. + * @param {Object} deviceFeature - Device feature. + * @param {Object} value - Value to send. + * @returns {Object} Return the value adapted. + * @example + * const value = bindValue({}, {}}, 1); + */ +function bindValue(device, deviceFeature, value) { + const { state } = getNodeStateInfoByExternalId(deviceFeature); + if (state === DEVICE_STATES.OCCUPANCY_STATE) { + return value === 0 ? 'noPersonInside' : 'personInside'; + } + if (state === DEVICE_STATES.HEATING_LEVEL_STATE) { + return HEATING_LEVELS[value]; + } + if (state === DEVICE_STATES.COMFORT_TEMPERATURE_STATE || state === DEVICE_STATES.ECO_TEMPERATURE_STATE) { + return parseFloat(value); + } + return value; +} + +/** + * @description Unbind value + * @param {Object} device - Device. + * @param {string} stateName - Device state name. + * @param {string} stateValue - Device state value. + * @returns {Object} Return the value adapted. + * @example + * const value = unbindValue({}, 'name', 1); + */ +function unbindValue(device, stateName, stateValue) { + if (stateName === DEVICE_STATES.OCCUPANCY_STATE) { + return stateValue === 'noPersonInside' ? 0 : 1; + } + if (stateName === DEVICE_STATES.HEATING_LEVEL_STATE) { + return HEATING_LEVELS.indexOf(stateValue); + } + return stateValue; +} + +module.exports = { + bindValue, + unbindValue, +}; diff --git a/server/services/overkiz/lib/utils/overkiz.constants.js b/server/services/overkiz/lib/utils/overkiz.constants.js new file mode 100644 index 0000000000..c4a28daeb0 --- /dev/null +++ b/server/services/overkiz/lib/utils/overkiz.constants.js @@ -0,0 +1,142 @@ +const DEVICE_FIRMWARE = 'FIRMWARE'; +const DEVICE_ONLINE = 'ONLINE'; + +const SUPPORTED_SERVERS = { + atlantic_cozytouch: { + name: 'Atlantic Cozytouch', + endpoint: 'https://ha110-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Atlantic', + jwt: true, + configuration: { + COZYTOUCH_ATLANTIC_API: 'https://api.groupe-atlantic.com', + COZYTOUCH_CLIENT_ID: 'czduc0RZZXdWbjVGbVV4UmlYN1pVSUM3ZFI4YTphSDEzOXZmbzA1ZGdqeDJkSFVSQkFTbmhCRW9h', + }, + configuration_url: undefined, + }, + hi_kumo_asia: { + name: 'Hitachi Hi Kumo (Asia)', + endpoint: 'https://ha203-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Hitachi', + configuration_url: undefined, + }, + hi_kumo_europe: { + name: 'Hitachi Hi Kumo (Europe)', + endpoint: 'https://ha117-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Hitachi', + configuration_url: undefined, + }, + hi_kumo_oceania: { + name: 'Hitachi Hi Kumo (Oceania)', + endpoint: 'https://ha203-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Hitachi', + configuration_url: undefined, + }, + nexity: { + name: 'Nexity Eugénie', + endpoint: 'https://ha106-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Nexity', + configuration: { + NEXITY_API: 'https://api.egn.prd.aws-nexity.fr', + NEXITY_COGNITO_CLIENT_ID: '3mca95jd5ase5lfde65rerovok', + NEXITY_COGNITO_USER_POOL: 'eu-west-1_wj277ucoI', + NEXITY_COGNITO_REGION: 'eu-west-1', + }, + configuration_url: undefined, + }, + rexel: { + name: 'Rexel Energeasy Connect', + endpoint: 'https://ha112-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Rexel', + configuration_url: 'https://utilisateur.energeasyconnect.com/user/#/zone/equipements', + }, + somfy_europe: { + // uses https://ha101-1.overkiz.com + name: 'Somfy (Europe)', + endpoint: 'https://tahomalink.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Somfy', + configuration_url: 'https://www.tahomalink.com', + }, + somfy_america: { + name: 'Somfy (North America)', + endpoint: 'https://ha401-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Somfy', + configuration_url: undefined, + }, + somfy_oceania: { + name: 'Somfy (Oceania)', + endpoint: 'https://ha201-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Somfy', + configuration_url: undefined, + }, +}; +const OVERKIZ_API = { + GET_DEVICES: 'setup/devices', + GET_GATEWAYS: 'setup/gateways', + GET_HISTORY_EXECUTIONS: 'history/executions', + GET_DEVICE_DEFINITION: 'setup/devices/%', + GET_DEVICE_STATE: 'setup/devices/%/states', + REFRESH_DEVICES_STATE: 'setup/devices/states/refresh', // For device that supports refresh +}; + +const OVERKIZ_SERVER_PARAM = { + OVERKIZ_TYPE: 'OVERKIZ_TYPE', + OVERKIZ_SERVER_USERNAME: 'OVERKIZ_SERVER_USERNAME', + OVERKIZ_SERVER_PASSWORD: 'OVERKIZ_SERVER_PASSWORD', +}; + +const DEVICE_TYPES = { + SYSTEM: 1, + SENSOR: 2, +}; + +const DEVICE_UID_CLASSES = { + POD: 'Pod', + PROTOCOL_GATEWAY: 'ProtocolGateway', + HEATER: 'HeatingSystem', + TEMPERATURE: 'TemperatureSensor', + CONTACT: 'ContactSensor', + OCCUPANCY: 'OccupancySensor', + ELECTRICITY: 'ElectricitySensor', +}; + +const DEVICE_STATES = { + MODEL_STATE: 'io:ModelState', + POWER_STATE: 'io:PowerState', + MANUFACTURER_NAME_STATE: 'core:ManufacturerNameState', + FIRMWARE_REVISION_STATE: 'core:FirmwareRevision', + STATUS_STATE: 'core:StatusState', + AWAY_STATE: 'core:HolidaysModeState', + HEATING_LEVEL_STATE: 'io:TargetHeatingLevelState', + OCCUPANCY_STATE: 'core:OccupancyState', + TEMPERATURE_STATE: 'core:TemperatureState', + COMFORT_TEMPERATURE_STATE: 'core:ComfortRoomTemperatureState', + ECO_TEMPERATURE_STATE: 'core:EcoRoomTemperatureState', + ON_OFF_STATE: 'core:OnOffState', + ELECTRIC_ENERGY_CONSUMTION_STATE: 'core:ElectricEnergyConsumptionState', +}; + +const DEVICE_COMMANDS = { + SET_CURRENT_OPERATING_MODE: 'setCurrentOperatingMode', + SET_HEATING_LEVEL: 'setHeatingLevel', + SET_ECO_TEMP: 'setEcoTemperature', + SET_COMFORT_TEMP: 'setComfortTemperature', + SET_AWAY_MODE: 'setHolidays', + REFRESH_HEATING_LEVEL: 'refreshHeatingLevel', + REFRESH_ECO_TEMPERATURE: 'refreshEcoTemperature', + REFRESH_COMFORT_TEMPERATURE: 'refreshComfortTemperature', +}; + +const HEATING_LEVELS = ['off', 'frost-protection', 'eco', 'comfort-2', 'comfort-1', 'comfort']; + +module.exports = { + SUPPORTED_SERVERS, + OVERKIZ_SERVER_PARAM, + OVERKIZ_API, + DEVICE_FIRMWARE, + DEVICE_ONLINE, + DEVICE_TYPES, + DEVICE_UID_CLASSES, + DEVICE_STATES, + DEVICE_COMMANDS, + HEATING_LEVELS, +}; diff --git a/server/services/overkiz/lib/utils/overkiz.externalId.js b/server/services/overkiz/lib/utils/overkiz.externalId.js new file mode 100644 index 0000000000..b6d5471704 --- /dev/null +++ b/server/services/overkiz/lib/utils/overkiz.externalId.js @@ -0,0 +1,70 @@ +/** + * @description Return name of device + * @param {Object} node - The zwave value. + * @returns {string} Return name. + * @example + * getDeviceName(node); + */ +function getDeviceName(node) { + return `${node.label} (${node.place})`; +} + +/** + * @description Return external id of device + * @param {Object} node - The zwave value. + * @returns {string} Return external id. + * @example + * getDeviceExternalId(node); + */ +function getDeviceExternalId(node) { + return `overkiz:deviceURL:${node.deviceURL}`; +} + +/** + * @description Return external id of deviceFeature + * @param {Object} node - The node feature. + * @param {Object} state - The node state feature. + * @returns {string} Return external id. + * @example + * getDeviceFeatureExternalId(node); + */ +function getDeviceFeatureExternalId(node, state) { + return `overkiz:deviceURL:${node.deviceURL}:state:${state}`; +} + +/** + * @description Return node info of device. + * @param {Object} device - The device. + * @returns {Object} Return all informations. + * @example + * getNodeInfoByExternalId({external_id: ''}); + */ +function getNodeInfoByExternalId(device) { + const array = device.external_id.split(':'); + return { + deviceURL: `${array[2]}:${array[3]}`, + }; +} + +/** + * @description Return node info of devicefeature. + * @param {Object} deviceFeature - The devicefeature. + * @returns {Object} Return all informations. + * @example + * getNodeStateInfoByExternalId({external_id: ''}); + */ +function getNodeStateInfoByExternalId(deviceFeature) { + const array = deviceFeature.external_id.split(':'); + return { + deviceURL: `${array[2]}:${array[3]}`, + state: `${array[5]}:${array[6]}`, + }; +} + +module.exports = { + getDeviceName, + getDeviceExternalId, + getDeviceFeatureExternalId, + getNodeInfoByExternalId, + getNodeStateInfoByExternalId, +}; diff --git a/server/services/overkiz/package-lock.json b/server/services/overkiz/package-lock.json new file mode 100644 index 0000000000..eef42ba840 --- /dev/null +++ b/server/services/overkiz/package-lock.json @@ -0,0 +1,48 @@ +{ + "name": "gladys-overkiz", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "requires": { + "retry": "0.13.1" + } + }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "requires": { + "follow-redirects": "^1.14.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" + }, + "follow-redirects": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", + "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + }, + "sleep-promise": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/sleep-promise/-/sleep-promise-9.1.0.tgz", + "integrity": "sha512-UHYzVpz9Xn8b+jikYSD6bqvf754xL2uBUzDFwiU6NcdZeifPr6UfgU43xpkPu67VMS88+TI2PSI7Eohgqf2fKA==" + } + } +} diff --git a/server/services/overkiz/package.json b/server/services/overkiz/package.json new file mode 100644 index 0000000000..6460d8cd47 --- /dev/null +++ b/server/services/overkiz/package.json @@ -0,0 +1,22 @@ +{ + "name": "gladys-overkiz", + "main": "index.js", + "os": [ + "darwin", + "linux", + "win32" + ], + "cpu": [ + "x64", + "arm", + "arm64" + ], + "scripts": {}, + "dependencies": { + "async-retry": "^1.3.3", + "axios": "^0.21.1", + "bluebird": "^3.7.0", + "bottleneck": "^2.19.5", + "sleep-promise": "^9.1.0" + } +} diff --git a/server/test/services/overkiz/controllers/overkiz.controller.test.js b/server/test/services/overkiz/controllers/overkiz.controller.test.js new file mode 100644 index 0000000000..9f50d1286d --- /dev/null +++ b/server/test/services/overkiz/controllers/overkiz.controller.test.js @@ -0,0 +1,85 @@ +const { assert, fake, stub } = require('sinon'); +const OverkizController = require('../../../../services/overkiz/api/overkiz.controller'); + +const userId = 'f2e704c9-4c79-41b3-a5bf-914dd1a16127'; + +const overkizService = { + config: stub(), + cleanUp: stub(), + enableCalendar: stub(), + disableCalendar: stub(), + syncUserCalendars: stub(), +}; + +const res = { + json: fake.returns(null), + status: fake.returns({ + send: fake.returns(null), + }), +}; + +describe('get /api/v1/service/overkiz/config', () => { + it('should return new config', async () => { + const overkizController = OverkizController(overkizService); + const req = { + user: { + id: userId, + }, + }; + await overkizController['get /api/v1/service/overkiz/config'].controller(req, res); + assert.calledWith(overkizService.config, userId); + }); +}); + +describe('get /api/v1/service/overkiz/cleanup', () => { + it('should cleanup overkiz data', async () => { + const overkizController = OverkizController(overkizService); + const req = { + user: { + id: userId, + }, + }; + await overkizController['get /api/v1/service/overkiz/cleanup'].controller(req, res); + assert.calledWith(overkizService.cleanUp, userId); + }); +}); + +describe('get /api/v1/service/overkiz/sync', () => { + it('should sync', async () => { + overkizService.syncUserCalendars.resolves({}); + const overkizController = OverkizController(overkizService); + const req = { + user: { + id: userId, + }, + }; + await overkizController['get /api/v1/service/overkiz/sync'].controller(req, res); + assert.calledWith(overkizService.syncUserCalendars, userId); + }); +}); + +describe('patch /api/v1/service/overkiz/enable', () => { + it('should enable overkiz calendar synchronization', async () => { + const overkizController = OverkizController(overkizService); + const req = { + body: { + selector: 'personnal', + }, + }; + await overkizController['patch /api/v1/service/overkiz/enable'].controller(req, res); + assert.calledWith(overkizService.enableCalendar, 'personnal'); + }); +}); + +describe('patch /api/v1/service/overkiz/disable', () => { + it('should disable overkiz calendar synchronization', async () => { + const overkizController = OverkizController(overkizService); + const req = { + body: { + selector: 'personnal', + }, + }; + await overkizController['patch /api/v1/service/overkiz/disable'].controller(req, res); + assert.calledWith(overkizService.disableCalendar, 'personnal'); + }); +}); diff --git a/server/test/services/overkiz/index.test.js b/server/test/services/overkiz/index.test.js new file mode 100644 index 0000000000..134ce7c9f1 --- /dev/null +++ b/server/test/services/overkiz/index.test.js @@ -0,0 +1,49 @@ +const { expect } = require('chai'); +const { stub, fake } = require('sinon'); + +const OverkizService = require('../../../services/overkiz/index'); + +const OVERKIZ_SERVICE_ID = 'OVERKIZ_SERVICE_ID'; + +describe('OverkizService', () => { + let gladys; + let overkizService; + + const values = { + OVERKIZ_TYPE: 'atlantic_cozytouch', + OVERKIZ_SERVER_USERNAME: 'pochet.romuald@gmail.com', + OVERKIZ_SERVER_PASSWORD: '8Vyr7acpcozytouch', + }; + + before(() => { + gladys = { + service: { + getLocalServiceByName: stub().resolves({ + id: OVERKIZ_SERVICE_ID, + }), + }, + event: { + emit: fake.returns(null), + }, + variable: { + getValue: (name) => values[name], + setValue: stub().resolves(null), + }, + }; + overkizService = OverkizService(gladys); + }); + + it('should start service', async () => { + await overkizService.start(); + expect(overkizService) + .to.have.property('start') + .and.be.instanceOf(Function); + }); + + it('should stop service', async () => { + await overkizService.stop(); + expect(overkizService) + .to.have.property('stop') + .and.be.instanceOf(Function); + }); +}); diff --git a/server/test/services/overkiz/lib/commands/overkiz.getOverkizDevices.test.js b/server/test/services/overkiz/lib/commands/overkiz.getOverkizDevices.test.js new file mode 100644 index 0000000000..205afba40f --- /dev/null +++ b/server/test/services/overkiz/lib/commands/overkiz.getOverkizDevices.test.js @@ -0,0 +1,8853 @@ +const { expect } = require('chai'); + +const OverkizHandler = require('../../../../../services/overkiz/lib/index'); + +const OVERKIZ_SERVICE_ID = 'OVERKIZ_SERVICE_ID'; + +describe('getOverkizDevices', () => { + let gladys; + let overkizHandler; + + before(() => { + gladys = {}; + overkizHandler = new OverkizHandler(gladys, OVERKIZ_SERVICE_ID); + }); + + it('should return no device', async () => { + overkizHandler.devices = {}; + overkizHandler.connected = true; + const devices = await overkizHandler.getOverkizDevices(); + expect(devices).to.deep.equal([]); + }); + + it('should return devices', async () => { + overkizHandler.devices = { + '50d30409-4949-4122-a674-aaacc0d28cc4': { + creationTime: 1586773014000, + lastUpdateTime: 1586773014000, + label: 'Box', + deviceURL: 'internal://0814-0291-7832/pod/0', + shortcut: false, + controllableName: 'internal:PodMiniComponent', + definition: { + commands: [ + { + commandName: 'getName', + nparams: 0, + }, + { + commandName: 'update', + nparams: 0, + }, + { + commandName: 'setCountryCode', + nparams: 1, + }, + { + commandName: 'activateCalendar', + nparams: 0, + }, + { + commandName: 'deactivateCalendar', + nparams: 0, + }, + { + commandName: 'refreshPodMode', + nparams: 0, + }, + { + commandName: 'refreshUpdateStatus', + nparams: 0, + }, + { + commandName: 'setCalendar', + nparams: 1, + }, + { + commandName: 'setLightingLedPodMode', + nparams: 1, + }, + { + commandName: 'setPodLedOff', + nparams: 0, + }, + { + commandName: 'setPodLedOn', + nparams: 0, + }, + ], + states: [ + { + type: 'DiscreteState', + values: ['offline', 'online'], + qualifiedName: 'core:ConnectivityState', + }, + { + type: 'DataState', + qualifiedName: 'core:CountryCodeState', + }, + { + type: 'DataState', + qualifiedName: 'core:LocalIPv4AddressState', + }, + { + type: 'DataState', + qualifiedName: 'core:NameState', + }, + { + type: 'DiscreteState', + values: ['doublePress', 'longPress', 'simplePress', 'triplePress', 'veryLongPress'], + qualifiedName: 'internal:LastActionConfigButtonState', + }, + { + type: 'ContinuousState', + qualifiedName: 'internal:LightingLedPodModeState', + }, + ], + dataProperties: [], + widgetName: 'Pod', + uiProfiles: ['UpdatableComponent'], + uiClass: 'Pod', + qualifiedName: 'internal:PodMiniComponent', + type: 'ACTUATOR', + }, + states: [ + { + name: 'core:NameState', + type: 3, + value: 'Box', + }, + { + name: 'internal:LightingLedPodModeState', + type: 2, + value: 1, + }, + { + name: 'core:CountryCodeState', + type: 3, + value: 'BE', + }, + { + name: 'core:LocalIPv4AddressState', + type: 3, + value: 'N/A', + }, + ], + available: true, + enabled: true, + placeOID: 'ebd3b36a-dd8f-4012-90c3-6ab51607e889', + widget: 'Pod', + type: 1, + oid: '50d30409-4949-4122-a674-aaacc0d28cc4', + uiClass: 'Pod', + }, + 'fbb6f179-92b4-479a-9c53-41607e3c7a15': { + creationTime: 1601921868000, + lastUpdateTime: 1601921868000, + label: 'Radiateur', + deviceURL: 'io://0814-0291-7832/11410052#1', + shortcut: false, + controllableName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + definition: { + commands: [ + { + commandName: 'advancedRefresh', + nparams: 1, + }, + { + commandName: 'cancelHeatingLevel', + nparams: 1, + }, + { + commandName: 'delayedStopIdentify', + nparams: 1, + }, + { + commandName: 'getName', + nparams: 0, + }, + { + commandName: 'identify', + nparams: 0, + }, + { + commandName: 'noPersonInside', + nparams: 0, + }, + { + commandName: 'off', + nparams: 0, + }, + { + commandName: 'personInside', + nparams: 0, + }, + { + commandName: 'refreshComfortTemperature', + nparams: 0, + }, + { + commandName: 'refreshDateTime', + nparams: 0, + }, + { + commandName: 'refreshDerogatedTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshEcoTemperature', + nparams: 0, + }, + { + commandName: 'refreshHeatingLevel', + nparams: 0, + }, + { + commandName: 'refreshIdentifier', + nparams: 0, + }, + { + commandName: 'refreshManufacturerName', + nparams: 0, + }, + { + commandName: 'refreshMaximumHeatingTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshMaximumTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshOperatingMode', + nparams: 0, + }, + { + commandName: 'refreshTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshTemperature', + nparams: 0, + }, + { + commandName: 'refreshTimeProgram', + nparams: 0, + }, + { + commandName: 'setComfortTemperature', + nparams: 1, + }, + { + commandName: 'setDateTime', + nparams: 1, + }, + { + commandName: 'setDerogatedTargetTemperature', + nparams: 1, + }, + { + commandName: 'setEcoTemperature', + nparams: 1, + }, + { + commandName: 'setHeatingLevel', + nparams: 1, + }, + { + commandName: 'setHeatingLevelWithTimer', + nparams: 2, + }, + { + commandName: 'setHolidays', + nparams: 1, + }, + { + commandName: 'setHolidaysTargetTemperature', + nparams: 1, + }, + { + commandName: 'setName', + nparams: 1, + }, + { + commandName: 'setOccupancyActivation', + nparams: 1, + }, + { + commandName: 'setOccupancy', + nparams: 1, + }, + { + commandName: 'setOpenWindowDetectionActivation', + nparams: 1, + }, + { + commandName: 'setOperatingMode', + nparams: 1, + }, + { + commandName: 'setPreviousTargetTemperature', + nparams: 1, + }, + { + commandName: 'setSchedulingType', + nparams: 1, + }, + { + commandName: 'setTargetTemperature', + nparams: 1, + }, + { + commandName: 'setTimeProgram', + nparams: 1, + }, + { + commandName: 'startIdentify', + nparams: 0, + }, + { + commandName: 'stopIdentify', + nparams: 0, + }, + { + commandName: 'wink', + nparams: 1, + }, + { + commandName: 'pairOneWayController', + nparams: 2, + }, + { + commandName: 'refreshAutoProgram', + nparams: 0, + }, + { + commandName: 'refreshControllerAddress', + nparams: 0, + }, + { + commandName: 'refreshCumulatedLowering', + nparams: 0, + }, + { + commandName: 'refreshCurrentWorkingRate', + nparams: 0, + }, + { + commandName: 'refreshDeletionCancelation', + nparams: 0, + }, + { + commandName: 'refreshEffectiveTemperatureSetpoint', + nparams: 0, + }, + { + commandName: 'refreshLocalLeadTime', + nparams: 0, + }, + { + commandName: 'refreshModel', + nparams: 0, + }, + { + commandName: 'refreshNativeFunctionalLevel', + nparams: 0, + }, + { + commandName: 'refreshPeakNotice', + nparams: 0, + }, + { + commandName: 'refreshPeakWarning', + nparams: 0, + }, + { + commandName: 'refreshPowerAndTension', + nparams: 0, + }, + { + commandName: 'refreshRoomDeletionThreshold', + nparams: 0, + }, + { + commandName: 'refreshSetpointLoweringTemperatureInProgMode', + nparams: 0, + }, + { + commandName: 'refreshSynchronisationRequest', + nparams: 0, + }, + { + commandName: 'refreshTemperatureProbeCalibrationOffset', + nparams: 0, + }, + { + commandName: 'setCommunicationTest', + nparams: 1, + }, + { + commandName: 'setDeletionCancelation', + nparams: 1, + }, + { + commandName: 'setExpectedPresence', + nparams: 1, + }, + { + commandName: 'setHeatingLevelForTrigger', + nparams: 1, + }, + { + commandName: 'setNativeLevelsList', + nparams: 1, + }, + { + commandName: 'setPeakNotice', + nparams: 1, + }, + { + commandName: 'setPeakWarning', + nparams: 1, + }, + { + commandName: 'setRoomDeletionThreshold', + nparams: 1, + }, + { + commandName: 'setSetpointLoweringTemperatureInProgMode', + nparams: 1, + }, + { + commandName: 'setTemperatureProbeCalibrationOffset', + nparams: 1, + }, + { + commandName: 'setTwinningExit', + nparams: 1, + }, + { + commandName: 'unpairAllOneWayControllers', + nparams: 0, + }, + { + commandName: 'unpairOneWayController', + nparams: 2, + }, + ], + states: [ + { + type: 'ContinuousState', + qualifiedName: 'core:ComfortRoomTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:DateTimeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:DerogatedTargetTemperatureState', + }, + { + type: 'DiscreteState', + values: ['good', 'low', 'normal', 'verylow'], + qualifiedName: 'core:DiscreteRSSILevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:EcoRoomTemperatureState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:HolidaysModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:HolidaysTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:IdentifierState', + }, + { + type: 'DataState', + qualifiedName: 'core:ManufacturerNameState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumHeatingTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:NameState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OccupancyActivationState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:OnOffState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OpenWindowDetectionActivationState', + }, + { + type: 'DiscreteState', + values: [ + 'antifreeze', + 'auto', + 'away', + 'eco', + 'frostprotection', + 'manual', + 'max', + 'normal', + 'off', + 'on', + 'prog', + 'program', + 'boost', + ], + qualifiedName: 'core:OperatingModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PreviousTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PriorityLockTimerState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:RSSILevelState', + }, + { + type: 'DiscreteState', + values: ['increase', 'none', 'standby'], + qualifiedName: 'core:RegulationModeState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:TargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:TimeProgramState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:VersionState', + }, + { + type: 'DataState', + qualifiedName: 'io:AutoProgramState', + }, + { + type: 'DataState', + qualifiedName: 'io:ControllerAddressState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CumulatedLoweringState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CurrentWorkingRateState', + }, + { + type: 'DiscreteState', + values: ['deletion cancelation', 'no deletion cancelation'], + qualifiedName: 'io:DeletionCancelationState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:EffectiveTemperatureSetpointState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:ExpectedPresenceState', + }, + { + type: 'DiscreteState', + values: ['external', 'internal'], + qualifiedName: 'io:InternalExternalSchedulingTypeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:LocalLeadTimeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:MaximumHeatingLevelState', + }, + { + type: 'DataState', + qualifiedName: 'io:ModelState', + }, + { + type: 'DiscreteState', + values: ['base', 'medium', 'top'], + qualifiedName: 'io:NativeFunctionalLevelState', + }, + { + type: 'DiscreteState', + values: ['long peak', 'no peak', 'short peak'], + qualifiedName: 'io:PeakNoticeState', + }, + { + type: 'DiscreteState', + values: ['long peak warning', 'no warning', 'short peak warning'], + qualifiedName: 'io:PeakWarningState', + }, + { + type: 'DataState', + qualifiedName: 'io:PowerState', + }, + { + type: 'DiscreteState', + values: [ + 'comfortLevel1', + 'comfortLevel2', + 'comfortLevel3', + 'comfortLevel4', + 'environmentProtection', + 'humanProtection', + 'userLevel1', + 'userLevel2', + ], + qualifiedName: 'io:PriorityLockLevelState', + }, + { + type: 'DiscreteState', + values: [ + 'LSC', + 'SAAC', + 'SFC', + 'UPS', + 'externalGateway', + 'localUser', + 'myself', + 'rain', + 'security', + 'temperature', + 'timer', + 'user', + 'wind', + ], + qualifiedName: 'io:PriorityLockOriginatorState', + }, + { + type: 'DataState', + qualifiedName: 'io:RoomDeletionThresholdState', + }, + { + type: 'DiscreteState', + values: ['kept', 'lost'], + qualifiedName: 'io:RunningState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:SetpointLoweringTemperatureInProgModeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:TargetHeatingLevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TemperatureProbeCalibrationOffsetState', + }, + { + type: 'DataState', + qualifiedName: 'io:TensionState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TimerForTransitoryStateState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:UptimeState', + }, + ], + dataProperties: [ + { + value: '500', + qualifiedName: 'core:identifyInterval', + }, + ], + widgetName: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + uiProfiles: ['StatefulOperatingModeHeating', 'OperatingModeHeating', 'StatefulThermostat', 'Thermostat'], + uiClass: 'HeatingSystem', + uiClassifiers: ['emitter'], + qualifiedName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + type: 'ACTUATOR', + }, + states: [ + { + name: 'core:NameState', + type: 3, + value: 'Radiateur', + }, + { + name: 'core:VersionState', + type: 3, + value: '49373431303038202020', + }, + { + name: 'core:PriorityLockTimerState', + type: 1, + value: 0, + }, + { + name: 'core:OnOffState', + type: 3, + value: 'on', + }, + { + name: 'io:TargetHeatingLevelState', + type: 3, + value: 'eco', + }, + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:DiscreteRSSILevelState', + type: 3, + value: 'normal', + }, + { + name: 'core:RSSILevelState', + type: 2, + value: 56, + }, + { + name: 'core:IdentifierState', + type: 3, + value: '00000000', + }, + { + name: 'io:MaximumHeatingLevelState', + type: 3, + value: 'unknown', + }, + { + name: 'io:TimerForTransitoryStateState', + type: 1, + value: 0, + }, + { + name: 'core:ComfortRoomTemperatureState', + type: 1, + value: 18, + }, + { + name: 'core:EcoRoomTemperatureState', + type: 1, + value: 7, + }, + { + name: 'core:OperatingModeState', + type: 3, + value: 'internal', + }, + { + name: 'core:OccupancyActivationState', + type: 3, + value: 'inactive', + }, + { + name: 'core:MaximumHeatingTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:MaximumTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:TargetTemperatureState', + type: 2, + value: 18, + }, + { + name: 'io:SetpointLoweringTemperatureInProgModeState', + type: 2, + value: 7, + }, + { + name: 'core:OpenWindowDetectionActivationState', + type: 3, + value: 'active', + }, + { + name: 'io:InternalExternalSchedulingTypeState', + type: 3, + value: 'internal', + }, + { + name: 'core:DateTimeState', + type: 11, + value: { + month: 3, + hour: 9, + year: 2018, + weekday: 5, + day: 10, + minute: 40, + second: 50, + }, + }, + { + name: 'io:LocalLeadTimeState', + type: 1, + value: 2269, + }, + { + name: 'core:RegulationModeState', + type: 3, + value: 'none', + }, + { + name: 'core:ManufacturerNameState', + type: 3, + value: 'Atlantic', + }, + { + name: 'io:ModelState', + type: 3, + value: 'AGILIA H PI-io', + }, + { + name: 'io:PowerState', + type: 1, + value: 750, + }, + { + name: 'io:TensionState', + type: 1, + value: 230, + }, + { + name: 'core:DerogatedTargetTemperatureState', + type: 2, + value: 0, + }, + { + name: 'io:NativeFunctionalLevelState', + type: 3, + value: 'Top', + }, + { + name: 'io:TemperatureProbeCalibrationOffsetState', + type: 2, + value: 0, + }, + { + name: 'io:CurrentWorkingRateState', + type: 2, + value: 0, + }, + { + name: 'io:CumulatedLoweringState', + type: 2, + value: 0, + }, + { + name: 'io:RoomDeletionThresholdState', + type: 3, + value: '-2°C', + }, + { + name: 'io:EffectiveTemperatureSetpointState', + type: 2, + value: 11, + }, + { + name: 'io:ControllerAddressState', + type: 1, + value: 11410051, + }, + { + name: 'io:ExpectedPresenceState', + type: 3, + value: '17:30', + lastUpdateTime: 1607184038000, + }, + { + name: 'io:AutoProgramState', + type: 11, + value: { + sunday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_NIV3', + 'CONF_2', + 'CONF_1', + 'CONF_2', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_2', + 'CONF_NIV2', + 'CONF_NIV1', + 'CONF_2', + 'CONF_NIV2', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_1', + 'CONF_1', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_2', + 'CONF_1', + 'CONF_1', + 'CONF_3_NIV2', + ], + saturday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_NIV1', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + ], + tuesday: [ + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_NIV3', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV2', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_1', + 'CONF_1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_NIV1', + 'CONF_NIV3', + 'CONF_1', + 'CONF_2', + 'CONF_2', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_1', + 'CONF_NIV1', + 'CONF_2', + 'CONF_NIV2', + 'CONF_3_NIV1', + ], + wednesday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV1', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_2', + 'CONF_1', + 'CONF_1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV2', + ], + thursday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_2', + 'CONF_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_NIV2', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + ], + friday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_2', + 'CONF_NIV3', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_NIV1', + 'CONF_2', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_2', + 'CONF_NIV2', + 'CONF_1', + 'CONF_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV2', + ], + anticipTime: 2269, + anticipNb: 20, + monday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_1', + 'CONF_2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + }, + }, + { + name: 'core:TimeProgramState', + type: 10, + value: [ + { + monday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + tuesday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + wednesday: [ + { + start: '06:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + thursday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + friday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + saturday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + sunday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + ], + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + ], + available: true, + enabled: true, + placeOID: '9abb0634-9b62-476f-8a60-0a63463e011b', + place: 'Salle de bain', + widget: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + type: 1, + oid: 'fbb6f179-92b4-479a-9c53-41607e3c7a15', + uiClass: 'HeatingSystem', + }, + '45eca6ef-5a88-4858-a84c-f9614258f966': { + creationTime: 1601921868000, + lastUpdateTime: 1601921868000, + label: 'IO (11410052#2)', + deviceURL: 'io://0814-0291-7832/11410052#2', + shortcut: false, + controllableName: 'io:TemperatureInCelciusIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:TemperatureState', + }, + ], + dataProperties: [], + widgetName: 'TemperatureSensor', + uiProfiles: ['Temperature'], + uiClass: 'TemperatureSensor', + qualifiedName: 'io:TemperatureInCelciusIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:TemperatureState', + type: 2, + value: 16.83, + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:MeasuredValueType', + type: 3, + value: 'core:TemperatureInCelcius', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + ], + available: true, + enabled: true, + placeOID: '9abb0634-9b62-476f-8a60-0a63463e011b', + place: 'Salle de bain', + widget: 'TemperatureSensor', + type: 2, + oid: '45eca6ef-5a88-4858-a84c-f9614258f966', + uiClass: 'TemperatureSensor', + }, + 'a158c7c4-65d3-4e31-b67a-c91e358a7c17': { + creationTime: 1601921868000, + lastUpdateTime: 1601921868000, + label: 'IO (11410052#3)', + deviceURL: 'io://0814-0291-7832/11410052#3', + shortcut: false, + controllableName: 'io:ContactIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + type: 'DiscreteState', + values: ['closed', 'open'], + qualifiedName: 'core:ContactState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + ], + dataProperties: [], + widgetName: 'ContactSensor', + uiProfiles: ['DoorContactSensor', 'ContactDetector'], + uiClass: 'ContactSensor', + qualifiedName: 'io:ContactIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:ContactState', + type: 3, + value: 'closed', + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + ], + available: true, + enabled: true, + placeOID: '9abb0634-9b62-476f-8a60-0a63463e011b', + place: 'Salle de bain', + widget: 'ContactSensor', + type: 2, + oid: 'a158c7c4-65d3-4e31-b67a-c91e358a7c17', + uiClass: 'ContactSensor', + }, + '2263edf8-95b5-41e8-8c59-a44c89aabe6f': { + creationTime: 1601921868000, + lastUpdateTime: 1601921868000, + label: 'IO (11410052#4)', + deviceURL: 'io://0814-0291-7832/11410052#4', + shortcut: false, + controllableName: 'io:OccupancyIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + eventBased: true, + type: 'DiscreteState', + values: ['noPersonInside', 'personInside'], + qualifiedName: 'core:OccupancyState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + ], + dataProperties: [], + widgetName: 'OccupancySensor', + uiProfiles: ['OccupancyDetector'], + uiClass: 'OccupancySensor', + qualifiedName: 'io:OccupancyIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:OccupancyState', + type: 3, + value: 'noPersonInside', + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + ], + available: true, + enabled: true, + placeOID: '9abb0634-9b62-476f-8a60-0a63463e011b', + place: 'Salle de bain', + widget: 'OccupancySensor', + type: 2, + oid: '2263edf8-95b5-41e8-8c59-a44c89aabe6f', + uiClass: 'OccupancySensor', + }, + '3d8317f1-5cfa-475d-9766-582909112fe0': { + creationTime: 1601921868000, + lastUpdateTime: 1601921868000, + label: 'IO (11410052#5)', + deviceURL: 'io://0814-0291-7832/11410052#5', + shortcut: false, + controllableName: 'io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff0State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff1State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff2State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff3State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff4State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff5State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff6State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff7State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff8State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff9State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ElectricEnergyConsumptionState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + ], + dataProperties: [], + widgetName: 'CumulativeElectricPowerConsumptionSensor', + uiProfiles: ['ElectricEnergyConsumption'], + uiClass: 'ElectricitySensor', + qualifiedName: 'io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:ElectricEnergyConsumptionState', + type: 1, + value: 312000, + }, + { + name: 'core:ConsumptionTariff1State', + type: 1, + value: 40000, + }, + { + name: 'core:ConsumptionTariff2State', + type: 1, + value: 100000, + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + { + name: 'core:MeasuredValueType', + type: 3, + value: 'core:ElectricalEnergyInWh', + }, + ], + available: true, + enabled: true, + placeOID: '9abb0634-9b62-476f-8a60-0a63463e011b', + place: 'Salle de bain', + widget: 'CumulativeElectricPowerConsumptionSensor', + type: 2, + oid: '3d8317f1-5cfa-475d-9766-582909112fe0', + uiClass: 'ElectricitySensor', + }, + 'c40edcea-4d8c-4223-af1c-696abd4e94ff': { + creationTime: 1601391514000, + lastUpdateTime: 1601391514000, + label: 'IO (15909334)', + deviceURL: 'io://0814-0291-7832/15909334', + shortcut: false, + controllableName: 'io:StackComponent', + definition: { + commands: [ + { + commandName: 'advancedSomfyDiscover', + nparams: 1, + }, + { + commandName: 'discover1WayController', + nparams: 2, + }, + { + commandName: 'discoverActuators', + nparams: 1, + }, + { + commandName: 'discoverSensors', + nparams: 1, + }, + { + commandName: 'discoverSomfyUnsetActuators', + nparams: 0, + }, + { + commandName: 'joinNetwork', + nparams: 0, + }, + { + commandName: 'resetNetworkSecurity', + nparams: 0, + }, + { + commandName: 'shareNetwork', + nparams: 0, + }, + ], + states: [], + dataProperties: [], + widgetName: 'IOStack', + uiProfiles: ['Specific'], + uiClass: 'ProtocolGateway', + qualifiedName: 'io:StackComponent', + type: 'PROTOCOL_GATEWAY', + }, + available: true, + enabled: true, + placeOID: 'ebd3b36a-dd8f-4012-90c3-6ab51607e889', + widget: 'IOStack', + type: 5, + oid: 'c40edcea-4d8c-4223-af1c-696abd4e94ff', + uiClass: 'ProtocolGateway', + }, + 'f2ca7610-248c-46a8-bf34-41edea559df5': { + creationTime: 1588332894000, + lastUpdateTime: 1588332894000, + label: 'Radiateur', + deviceURL: 'io://0814-0291-7832/5276217#1', + shortcut: false, + controllableName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + definition: { + commands: [ + { + commandName: 'advancedRefresh', + nparams: 1, + }, + { + commandName: 'cancelHeatingLevel', + nparams: 1, + }, + { + commandName: 'delayedStopIdentify', + nparams: 1, + }, + { + commandName: 'getName', + nparams: 0, + }, + { + commandName: 'identify', + nparams: 0, + }, + { + commandName: 'noPersonInside', + nparams: 0, + }, + { + commandName: 'off', + nparams: 0, + }, + { + commandName: 'personInside', + nparams: 0, + }, + { + commandName: 'refreshComfortTemperature', + nparams: 0, + }, + { + commandName: 'refreshDateTime', + nparams: 0, + }, + { + commandName: 'refreshDerogatedTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshEcoTemperature', + nparams: 0, + }, + { + commandName: 'refreshHeatingLevel', + nparams: 0, + }, + { + commandName: 'refreshIdentifier', + nparams: 0, + }, + { + commandName: 'refreshManufacturerName', + nparams: 0, + }, + { + commandName: 'refreshMaximumHeatingTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshMaximumTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshOperatingMode', + nparams: 0, + }, + { + commandName: 'refreshTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshTemperature', + nparams: 0, + }, + { + commandName: 'refreshTimeProgram', + nparams: 0, + }, + { + commandName: 'setComfortTemperature', + nparams: 1, + }, + { + commandName: 'setDateTime', + nparams: 1, + }, + { + commandName: 'setDerogatedTargetTemperature', + nparams: 1, + }, + { + commandName: 'setEcoTemperature', + nparams: 1, + }, + { + commandName: 'setHeatingLevel', + nparams: 1, + }, + { + commandName: 'setHeatingLevelWithTimer', + nparams: 2, + }, + { + commandName: 'setHolidays', + nparams: 1, + }, + { + commandName: 'setHolidaysTargetTemperature', + nparams: 1, + }, + { + commandName: 'setName', + nparams: 1, + }, + { + commandName: 'setOccupancyActivation', + nparams: 1, + }, + { + commandName: 'setOccupancy', + nparams: 1, + }, + { + commandName: 'setOpenWindowDetectionActivation', + nparams: 1, + }, + { + commandName: 'setOperatingMode', + nparams: 1, + }, + { + commandName: 'setPreviousTargetTemperature', + nparams: 1, + }, + { + commandName: 'setSchedulingType', + nparams: 1, + }, + { + commandName: 'setTargetTemperature', + nparams: 1, + }, + { + commandName: 'setTimeProgram', + nparams: 1, + }, + { + commandName: 'startIdentify', + nparams: 0, + }, + { + commandName: 'stopIdentify', + nparams: 0, + }, + { + commandName: 'wink', + nparams: 1, + }, + { + commandName: 'pairOneWayController', + nparams: 2, + }, + { + commandName: 'refreshAutoProgram', + nparams: 0, + }, + { + commandName: 'refreshControllerAddress', + nparams: 0, + }, + { + commandName: 'refreshCumulatedLowering', + nparams: 0, + }, + { + commandName: 'refreshCurrentWorkingRate', + nparams: 0, + }, + { + commandName: 'refreshDeletionCancelation', + nparams: 0, + }, + { + commandName: 'refreshEffectiveTemperatureSetpoint', + nparams: 0, + }, + { + commandName: 'refreshLocalLeadTime', + nparams: 0, + }, + { + commandName: 'refreshModel', + nparams: 0, + }, + { + commandName: 'refreshNativeFunctionalLevel', + nparams: 0, + }, + { + commandName: 'refreshPeakNotice', + nparams: 0, + }, + { + commandName: 'refreshPeakWarning', + nparams: 0, + }, + { + commandName: 'refreshPowerAndTension', + nparams: 0, + }, + { + commandName: 'refreshRoomDeletionThreshold', + nparams: 0, + }, + { + commandName: 'refreshSetpointLoweringTemperatureInProgMode', + nparams: 0, + }, + { + commandName: 'refreshSynchronisationRequest', + nparams: 0, + }, + { + commandName: 'refreshTemperatureProbeCalibrationOffset', + nparams: 0, + }, + { + commandName: 'setCommunicationTest', + nparams: 1, + }, + { + commandName: 'setDeletionCancelation', + nparams: 1, + }, + { + commandName: 'setExpectedPresence', + nparams: 1, + }, + { + commandName: 'setHeatingLevelForTrigger', + nparams: 1, + }, + { + commandName: 'setNativeLevelsList', + nparams: 1, + }, + { + commandName: 'setPeakNotice', + nparams: 1, + }, + { + commandName: 'setPeakWarning', + nparams: 1, + }, + { + commandName: 'setRoomDeletionThreshold', + nparams: 1, + }, + { + commandName: 'setSetpointLoweringTemperatureInProgMode', + nparams: 1, + }, + { + commandName: 'setTemperatureProbeCalibrationOffset', + nparams: 1, + }, + { + commandName: 'setTwinningExit', + nparams: 1, + }, + { + commandName: 'unpairAllOneWayControllers', + nparams: 0, + }, + { + commandName: 'unpairOneWayController', + nparams: 2, + }, + ], + states: [ + { + type: 'ContinuousState', + qualifiedName: 'core:ComfortRoomTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:DateTimeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:DerogatedTargetTemperatureState', + }, + { + type: 'DiscreteState', + values: ['good', 'low', 'normal', 'verylow'], + qualifiedName: 'core:DiscreteRSSILevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:EcoRoomTemperatureState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:HolidaysModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:HolidaysTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:IdentifierState', + }, + { + type: 'DataState', + qualifiedName: 'core:ManufacturerNameState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumHeatingTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:NameState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OccupancyActivationState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:OnOffState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OpenWindowDetectionActivationState', + }, + { + type: 'DiscreteState', + values: [ + 'antifreeze', + 'auto', + 'away', + 'eco', + 'frostprotection', + 'manual', + 'max', + 'normal', + 'off', + 'on', + 'prog', + 'program', + 'boost', + ], + qualifiedName: 'core:OperatingModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PreviousTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PriorityLockTimerState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:RSSILevelState', + }, + { + type: 'DiscreteState', + values: ['increase', 'none', 'standby'], + qualifiedName: 'core:RegulationModeState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:TargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:TimeProgramState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:VersionState', + }, + { + type: 'DataState', + qualifiedName: 'io:AutoProgramState', + }, + { + type: 'DataState', + qualifiedName: 'io:ControllerAddressState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CumulatedLoweringState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CurrentWorkingRateState', + }, + { + type: 'DiscreteState', + values: ['deletion cancelation', 'no deletion cancelation'], + qualifiedName: 'io:DeletionCancelationState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:EffectiveTemperatureSetpointState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:ExpectedPresenceState', + }, + { + type: 'DiscreteState', + values: ['external', 'internal'], + qualifiedName: 'io:InternalExternalSchedulingTypeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:LocalLeadTimeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:MaximumHeatingLevelState', + }, + { + type: 'DataState', + qualifiedName: 'io:ModelState', + }, + { + type: 'DiscreteState', + values: ['base', 'medium', 'top'], + qualifiedName: 'io:NativeFunctionalLevelState', + }, + { + type: 'DiscreteState', + values: ['long peak', 'no peak', 'short peak'], + qualifiedName: 'io:PeakNoticeState', + }, + { + type: 'DiscreteState', + values: ['long peak warning', 'no warning', 'short peak warning'], + qualifiedName: 'io:PeakWarningState', + }, + { + type: 'DataState', + qualifiedName: 'io:PowerState', + }, + { + type: 'DiscreteState', + values: [ + 'comfortLevel1', + 'comfortLevel2', + 'comfortLevel3', + 'comfortLevel4', + 'environmentProtection', + 'humanProtection', + 'userLevel1', + 'userLevel2', + ], + qualifiedName: 'io:PriorityLockLevelState', + }, + { + type: 'DiscreteState', + values: [ + 'LSC', + 'SAAC', + 'SFC', + 'UPS', + 'externalGateway', + 'localUser', + 'myself', + 'rain', + 'security', + 'temperature', + 'timer', + 'user', + 'wind', + ], + qualifiedName: 'io:PriorityLockOriginatorState', + }, + { + type: 'DataState', + qualifiedName: 'io:RoomDeletionThresholdState', + }, + { + type: 'DiscreteState', + values: ['kept', 'lost'], + qualifiedName: 'io:RunningState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:SetpointLoweringTemperatureInProgModeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:TargetHeatingLevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TemperatureProbeCalibrationOffsetState', + }, + { + type: 'DataState', + qualifiedName: 'io:TensionState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TimerForTransitoryStateState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:UptimeState', + }, + ], + dataProperties: [ + { + value: '500', + qualifiedName: 'core:identifyInterval', + }, + ], + widgetName: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + uiProfiles: ['StatefulOperatingModeHeating', 'OperatingModeHeating', 'StatefulThermostat', 'Thermostat'], + uiClass: 'HeatingSystem', + uiClassifiers: ['emitter'], + qualifiedName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + type: 'ACTUATOR', + }, + states: [ + { + name: 'core:NameState', + type: 3, + value: 'Radiateur', + }, + { + name: 'core:VersionState', + type: 3, + value: '49373431303038202020', + }, + { + name: 'core:PriorityLockTimerState', + type: 1, + value: 0, + }, + { + name: 'core:OnOffState', + type: 3, + value: 'on', + }, + { + name: 'io:TargetHeatingLevelState', + type: 3, + value: 'comfort', + }, + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:DiscreteRSSILevelState', + type: 3, + value: 'normal', + }, + { + name: 'core:RSSILevelState', + type: 2, + value: 66, + }, + { + name: 'core:IdentifierState', + type: 3, + value: '00000000', + }, + { + name: 'io:MaximumHeatingLevelState', + type: 3, + value: 'unknown', + }, + { + name: 'io:TimerForTransitoryStateState', + type: 1, + value: 0, + }, + { + name: 'core:ComfortRoomTemperatureState', + type: 1, + value: 14, + }, + { + name: 'core:EcoRoomTemperatureState', + type: 1, + value: 4, + }, + { + name: 'core:OperatingModeState', + type: 3, + value: 'auto', + }, + { + name: 'core:OccupancyActivationState', + type: 3, + value: 'active', + }, + { + name: 'core:MaximumHeatingTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:MaximumTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:TargetTemperatureState', + type: 2, + value: 14, + }, + { + name: 'io:SetpointLoweringTemperatureInProgModeState', + type: 2, + value: 4, + }, + { + name: 'core:OpenWindowDetectionActivationState', + type: 3, + value: 'active', + }, + { + name: 'io:InternalExternalSchedulingTypeState', + type: 3, + value: 'internal', + }, + { + name: 'core:DateTimeState', + type: 11, + value: { + month: 3, + hour: 9, + year: 2018, + weekday: 5, + day: 10, + minute: 40, + second: 14, + }, + }, + { + name: 'io:LocalLeadTimeState', + type: 1, + value: 1737, + }, + { + name: 'core:RegulationModeState', + type: 3, + value: 'none', + }, + { + name: 'core:ManufacturerNameState', + type: 3, + value: 'Atlantic', + }, + { + name: 'io:ModelState', + type: 3, + value: 'AGILIA H PI-io', + }, + { + name: 'io:PowerState', + type: 1, + value: 750, + }, + { + name: 'io:TensionState', + type: 1, + value: 230, + }, + { + name: 'core:DerogatedTargetTemperatureState', + type: 2, + value: 0, + }, + { + name: 'io:NativeFunctionalLevelState', + type: 3, + value: 'Top', + }, + { + name: 'io:TemperatureProbeCalibrationOffsetState', + type: 2, + value: 0, + }, + { + name: 'io:CurrentWorkingRateState', + type: 2, + value: 0, + }, + { + name: 'io:CumulatedLoweringState', + type: 2, + value: 91, + }, + { + name: 'io:RoomDeletionThresholdState', + type: 3, + value: '-2°C', + }, + { + name: 'io:EffectiveTemperatureSetpointState', + type: 2, + value: 14, + }, + { + name: 'io:ControllerAddressState', + type: 1, + value: 5276216, + }, + { + name: 'io:ExpectedPresenceState', + type: 3, + value: '19:30', + lastUpdateTime: 1607019810000, + }, + { + name: 'io:AutoProgramState', + type: 11, + value: { + sunday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + saturday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + tuesday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + wednesday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + ], + thursday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + ], + friday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + ], + anticipTime: 1737, + anticipNb: 20, + monday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + }, + }, + { + name: 'core:PreviousTargetTemperatureState', + type: 2, + value: 18, + }, + { + name: 'core:TimeProgramState', + type: 10, + value: [ + { + monday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + tuesday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + wednesday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + thursday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + friday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + saturday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + sunday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + ], + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + ], + available: true, + enabled: true, + placeOID: 'dab51ec0-5b0c-4694-8389-7498f02d6ee6', + place: 'Parents', + widget: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + type: 1, + oid: 'f2ca7610-248c-46a8-bf34-41edea559df5', + uiClass: 'HeatingSystem', + }, + 'b8ea4ea5-9eb2-4d79-989b-1c73eeb5e458': { + creationTime: 1588332894000, + lastUpdateTime: 1588332894000, + label: 'IO (5276217#2)', + deviceURL: 'io://0814-0291-7832/5276217#2', + shortcut: false, + controllableName: 'io:TemperatureInCelciusIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:TemperatureState', + }, + ], + dataProperties: [], + widgetName: 'TemperatureSensor', + uiProfiles: ['Temperature'], + uiClass: 'TemperatureSensor', + qualifiedName: 'io:TemperatureInCelciusIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:TemperatureState', + type: 2, + value: 16.62, + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:MeasuredValueType', + type: 3, + value: 'core:TemperatureInCelcius', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + ], + available: true, + enabled: true, + placeOID: 'dab51ec0-5b0c-4694-8389-7498f02d6ee6', + place: 'Parents', + widget: 'TemperatureSensor', + type: 2, + oid: 'b8ea4ea5-9eb2-4d79-989b-1c73eeb5e458', + uiClass: 'TemperatureSensor', + }, + '3105090e-b643-4962-91da-e783edf7c19f': { + creationTime: 1588332894000, + lastUpdateTime: 1588332894000, + label: 'IO (5276217#3)', + deviceURL: 'io://0814-0291-7832/5276217#3', + shortcut: false, + controllableName: 'io:ContactIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + type: 'DiscreteState', + values: ['closed', 'open'], + qualifiedName: 'core:ContactState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + ], + dataProperties: [], + widgetName: 'ContactSensor', + uiProfiles: ['DoorContactSensor', 'ContactDetector'], + uiClass: 'ContactSensor', + qualifiedName: 'io:ContactIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:ContactState', + type: 3, + value: 'closed', + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + ], + available: true, + enabled: true, + placeOID: 'dab51ec0-5b0c-4694-8389-7498f02d6ee6', + place: 'Parents', + widget: 'ContactSensor', + type: 2, + oid: '3105090e-b643-4962-91da-e783edf7c19f', + uiClass: 'ContactSensor', + }, + '4a2301c2-3793-47eb-b7d9-ea73b7172f2e': { + creationTime: 1588332894000, + lastUpdateTime: 1588332894000, + label: 'IO (5276217#4)', + deviceURL: 'io://0814-0291-7832/5276217#4', + shortcut: false, + controllableName: 'io:OccupancyIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + eventBased: true, + type: 'DiscreteState', + values: ['noPersonInside', 'personInside'], + qualifiedName: 'core:OccupancyState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + ], + dataProperties: [], + widgetName: 'OccupancySensor', + uiProfiles: ['OccupancyDetector'], + uiClass: 'OccupancySensor', + qualifiedName: 'io:OccupancyIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:OccupancyState', + type: 3, + value: 'noPersonInside', + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + ], + available: true, + enabled: true, + placeOID: 'dab51ec0-5b0c-4694-8389-7498f02d6ee6', + place: 'Parents', + widget: 'OccupancySensor', + type: 2, + oid: '4a2301c2-3793-47eb-b7d9-ea73b7172f2e', + uiClass: 'OccupancySensor', + }, + 'cb623839-1213-41b3-a67e-b5e0c80e9141': { + creationTime: 1588332894000, + lastUpdateTime: 1588332894000, + label: 'IO (5276217#5)', + deviceURL: 'io://0814-0291-7832/5276217#5', + shortcut: false, + controllableName: 'io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff0State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff1State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff2State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff3State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff4State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff5State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff6State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff7State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff8State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff9State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ElectricEnergyConsumptionState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + ], + dataProperties: [], + widgetName: 'CumulativeElectricPowerConsumptionSensor', + uiProfiles: ['ElectricEnergyConsumption'], + uiClass: 'ElectricitySensor', + qualifiedName: 'io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:ElectricEnergyConsumptionState', + type: 1, + value: 157000, + }, + { + name: 'core:ConsumptionTariff1State', + type: 1, + value: 30000, + }, + { + name: 'core:ConsumptionTariff2State', + type: 1, + value: 69000, + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + { + name: 'core:MeasuredValueType', + type: 3, + value: 'core:ElectricalEnergyInWh', + }, + ], + available: true, + enabled: true, + placeOID: 'dab51ec0-5b0c-4694-8389-7498f02d6ee6', + place: 'Parents', + widget: 'CumulativeElectricPowerConsumptionSensor', + type: 2, + oid: 'cb623839-1213-41b3-a67e-b5e0c80e9141', + uiClass: 'ElectricitySensor', + }, + '29bbe178-d3e3-4322-85dd-cafc8148cf41': { + creationTime: 1586773220000, + lastUpdateTime: 1586773220000, + label: 'Radiateur', + deviceURL: 'io://0814-0291-7832/6412161#1', + shortcut: false, + controllableName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + definition: { + commands: [ + { + commandName: 'advancedRefresh', + nparams: 1, + }, + { + commandName: 'cancelHeatingLevel', + nparams: 1, + }, + { + commandName: 'delayedStopIdentify', + nparams: 1, + }, + { + commandName: 'getName', + nparams: 0, + }, + { + commandName: 'identify', + nparams: 0, + }, + { + commandName: 'noPersonInside', + nparams: 0, + }, + { + commandName: 'off', + nparams: 0, + }, + { + commandName: 'personInside', + nparams: 0, + }, + { + commandName: 'refreshComfortTemperature', + nparams: 0, + }, + { + commandName: 'refreshDateTime', + nparams: 0, + }, + { + commandName: 'refreshDerogatedTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshEcoTemperature', + nparams: 0, + }, + { + commandName: 'refreshHeatingLevel', + nparams: 0, + }, + { + commandName: 'refreshIdentifier', + nparams: 0, + }, + { + commandName: 'refreshManufacturerName', + nparams: 0, + }, + { + commandName: 'refreshMaximumHeatingTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshMaximumTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshOperatingMode', + nparams: 0, + }, + { + commandName: 'refreshTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshTemperature', + nparams: 0, + }, + { + commandName: 'refreshTimeProgram', + nparams: 0, + }, + { + commandName: 'setComfortTemperature', + nparams: 1, + }, + { + commandName: 'setDateTime', + nparams: 1, + }, + { + commandName: 'setDerogatedTargetTemperature', + nparams: 1, + }, + { + commandName: 'setEcoTemperature', + nparams: 1, + }, + { + commandName: 'setHeatingLevel', + nparams: 1, + }, + { + commandName: 'setHeatingLevelWithTimer', + nparams: 2, + }, + { + commandName: 'setHolidays', + nparams: 1, + }, + { + commandName: 'setHolidaysTargetTemperature', + nparams: 1, + }, + { + commandName: 'setName', + nparams: 1, + }, + { + commandName: 'setOccupancyActivation', + nparams: 1, + }, + { + commandName: 'setOccupancy', + nparams: 1, + }, + { + commandName: 'setOpenWindowDetectionActivation', + nparams: 1, + }, + { + commandName: 'setOperatingMode', + nparams: 1, + }, + { + commandName: 'setPreviousTargetTemperature', + nparams: 1, + }, + { + commandName: 'setSchedulingType', + nparams: 1, + }, + { + commandName: 'setTargetTemperature', + nparams: 1, + }, + { + commandName: 'setTimeProgram', + nparams: 1, + }, + { + commandName: 'startIdentify', + nparams: 0, + }, + { + commandName: 'stopIdentify', + nparams: 0, + }, + { + commandName: 'wink', + nparams: 1, + }, + { + commandName: 'pairOneWayController', + nparams: 2, + }, + { + commandName: 'refreshAutoProgram', + nparams: 0, + }, + { + commandName: 'refreshControllerAddress', + nparams: 0, + }, + { + commandName: 'refreshCumulatedLowering', + nparams: 0, + }, + { + commandName: 'refreshCurrentWorkingRate', + nparams: 0, + }, + { + commandName: 'refreshDeletionCancelation', + nparams: 0, + }, + { + commandName: 'refreshEffectiveTemperatureSetpoint', + nparams: 0, + }, + { + commandName: 'refreshLocalLeadTime', + nparams: 0, + }, + { + commandName: 'refreshModel', + nparams: 0, + }, + { + commandName: 'refreshNativeFunctionalLevel', + nparams: 0, + }, + { + commandName: 'refreshPeakNotice', + nparams: 0, + }, + { + commandName: 'refreshPeakWarning', + nparams: 0, + }, + { + commandName: 'refreshPowerAndTension', + nparams: 0, + }, + { + commandName: 'refreshRoomDeletionThreshold', + nparams: 0, + }, + { + commandName: 'refreshSetpointLoweringTemperatureInProgMode', + nparams: 0, + }, + { + commandName: 'refreshSynchronisationRequest', + nparams: 0, + }, + { + commandName: 'refreshTemperatureProbeCalibrationOffset', + nparams: 0, + }, + { + commandName: 'setCommunicationTest', + nparams: 1, + }, + { + commandName: 'setDeletionCancelation', + nparams: 1, + }, + { + commandName: 'setExpectedPresence', + nparams: 1, + }, + { + commandName: 'setHeatingLevelForTrigger', + nparams: 1, + }, + { + commandName: 'setNativeLevelsList', + nparams: 1, + }, + { + commandName: 'setPeakNotice', + nparams: 1, + }, + { + commandName: 'setPeakWarning', + nparams: 1, + }, + { + commandName: 'setRoomDeletionThreshold', + nparams: 1, + }, + { + commandName: 'setSetpointLoweringTemperatureInProgMode', + nparams: 1, + }, + { + commandName: 'setTemperatureProbeCalibrationOffset', + nparams: 1, + }, + { + commandName: 'setTwinningExit', + nparams: 1, + }, + { + commandName: 'unpairAllOneWayControllers', + nparams: 0, + }, + { + commandName: 'unpairOneWayController', + nparams: 2, + }, + ], + states: [ + { + type: 'ContinuousState', + qualifiedName: 'core:ComfortRoomTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:DateTimeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:DerogatedTargetTemperatureState', + }, + { + type: 'DiscreteState', + values: ['good', 'low', 'normal', 'verylow'], + qualifiedName: 'core:DiscreteRSSILevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:EcoRoomTemperatureState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:HolidaysModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:HolidaysTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:IdentifierState', + }, + { + type: 'DataState', + qualifiedName: 'core:ManufacturerNameState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumHeatingTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:NameState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OccupancyActivationState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:OnOffState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OpenWindowDetectionActivationState', + }, + { + type: 'DiscreteState', + values: [ + 'antifreeze', + 'auto', + 'away', + 'eco', + 'frostprotection', + 'manual', + 'max', + 'normal', + 'off', + 'on', + 'prog', + 'program', + 'boost', + ], + qualifiedName: 'core:OperatingModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PreviousTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PriorityLockTimerState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:RSSILevelState', + }, + { + type: 'DiscreteState', + values: ['increase', 'none', 'standby'], + qualifiedName: 'core:RegulationModeState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:TargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:TimeProgramState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:VersionState', + }, + { + type: 'DataState', + qualifiedName: 'io:AutoProgramState', + }, + { + type: 'DataState', + qualifiedName: 'io:ControllerAddressState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CumulatedLoweringState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CurrentWorkingRateState', + }, + { + type: 'DiscreteState', + values: ['deletion cancelation', 'no deletion cancelation'], + qualifiedName: 'io:DeletionCancelationState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:EffectiveTemperatureSetpointState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:ExpectedPresenceState', + }, + { + type: 'DiscreteState', + values: ['external', 'internal'], + qualifiedName: 'io:InternalExternalSchedulingTypeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:LocalLeadTimeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:MaximumHeatingLevelState', + }, + { + type: 'DataState', + qualifiedName: 'io:ModelState', + }, + { + type: 'DiscreteState', + values: ['base', 'medium', 'top'], + qualifiedName: 'io:NativeFunctionalLevelState', + }, + { + type: 'DiscreteState', + values: ['long peak', 'no peak', 'short peak'], + qualifiedName: 'io:PeakNoticeState', + }, + { + type: 'DiscreteState', + values: ['long peak warning', 'no warning', 'short peak warning'], + qualifiedName: 'io:PeakWarningState', + }, + { + type: 'DataState', + qualifiedName: 'io:PowerState', + }, + { + type: 'DiscreteState', + values: [ + 'comfortLevel1', + 'comfortLevel2', + 'comfortLevel3', + 'comfortLevel4', + 'environmentProtection', + 'humanProtection', + 'userLevel1', + 'userLevel2', + ], + qualifiedName: 'io:PriorityLockLevelState', + }, + { + type: 'DiscreteState', + values: [ + 'LSC', + 'SAAC', + 'SFC', + 'UPS', + 'externalGateway', + 'localUser', + 'myself', + 'rain', + 'security', + 'temperature', + 'timer', + 'user', + 'wind', + ], + qualifiedName: 'io:PriorityLockOriginatorState', + }, + { + type: 'DataState', + qualifiedName: 'io:RoomDeletionThresholdState', + }, + { + type: 'DiscreteState', + values: ['kept', 'lost'], + qualifiedName: 'io:RunningState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:SetpointLoweringTemperatureInProgModeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:TargetHeatingLevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TemperatureProbeCalibrationOffsetState', + }, + { + type: 'DataState', + qualifiedName: 'io:TensionState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TimerForTransitoryStateState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:UptimeState', + }, + ], + dataProperties: [ + { + value: '500', + qualifiedName: 'core:identifyInterval', + }, + ], + widgetName: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + uiProfiles: ['StatefulOperatingModeHeating', 'OperatingModeHeating', 'StatefulThermostat', 'Thermostat'], + uiClass: 'HeatingSystem', + uiClassifiers: ['emitter'], + qualifiedName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + type: 'ACTUATOR', + }, + states: [ + { + name: 'core:NameState', + type: 3, + value: 'Radiateur', + }, + { + name: 'core:VersionState', + type: 3, + value: '49373431303038202020', + }, + { + name: 'core:PriorityLockTimerState', + type: 1, + value: 0, + }, + { + name: 'core:OnOffState', + type: 3, + value: 'on', + }, + { + name: 'io:TargetHeatingLevelState', + type: 3, + value: 'comfort', + }, + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:DiscreteRSSILevelState', + type: 3, + value: 'normal', + }, + { + name: 'core:RSSILevelState', + type: 2, + value: 78, + }, + { + name: 'core:IdentifierState', + type: 3, + value: '00000000', + }, + { + name: 'io:MaximumHeatingLevelState', + type: 3, + value: 'unknown', + }, + { + name: 'io:TimerForTransitoryStateState', + type: 1, + value: 0, + }, + { + name: 'core:ComfortRoomTemperatureState', + type: 1, + value: 16, + }, + { + name: 'core:EcoRoomTemperatureState', + type: 2, + value: 4.5, + }, + { + name: 'core:OperatingModeState', + type: 3, + value: 'auto', + }, + { + name: 'core:OccupancyActivationState', + type: 3, + value: 'inactive', + }, + { + name: 'core:MaximumHeatingTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:MaximumTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:TargetTemperatureState', + type: 2, + value: 16, + }, + { + name: 'io:SetpointLoweringTemperatureInProgModeState', + type: 2, + value: 4.5, + }, + { + name: 'core:OpenWindowDetectionActivationState', + type: 3, + value: 'inactive', + }, + { + name: 'io:InternalExternalSchedulingTypeState', + type: 3, + value: 'internal', + }, + { + name: 'core:DateTimeState', + type: 11, + value: { + month: 3, + hour: 9, + year: 2018, + weekday: 5, + day: 10, + minute: 40, + second: 47, + }, + }, + { + name: 'io:LocalLeadTimeState', + type: 1, + value: 1598, + }, + { + name: 'core:RegulationModeState', + type: 3, + value: 'standby', + }, + { + name: 'core:ManufacturerNameState', + type: 3, + value: 'Atlantic', + }, + { + name: 'io:ModelState', + type: 3, + value: 'AGILIA H PI-io', + }, + { + name: 'io:PowerState', + type: 1, + value: 750, + }, + { + name: 'io:TensionState', + type: 1, + value: 230, + }, + { + name: 'core:DerogatedTargetTemperatureState', + type: 2, + value: 0, + }, + { + name: 'io:NativeFunctionalLevelState', + type: 3, + value: 'Top', + }, + { + name: 'io:TemperatureProbeCalibrationOffsetState', + type: 2, + value: 0, + }, + { + name: 'io:CurrentWorkingRateState', + type: 2, + value: 0, + }, + { + name: 'io:CumulatedLoweringState', + type: 2, + value: 0, + }, + { + name: 'io:RoomDeletionThresholdState', + type: 3, + value: '-2°C', + }, + { + name: 'io:EffectiveTemperatureSetpointState', + type: 2, + value: 16, + }, + { + name: 'io:ControllerAddressState', + type: 1, + value: 6412160, + }, + { + name: 'io:ExpectedPresenceState', + type: 3, + value: '20:30', + lastUpdateTime: 1601921551000, + }, + { + name: 'io:AutoProgramState', + type: 11, + value: { + sunday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + saturday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_1', + 'CONF_1', + 'CONF_2', + 'CONF_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + tuesday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_1', + 'CONF_1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + wednesday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_NIV2', + 'CONF_1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + thursday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + friday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + anticipTime: 1598, + anticipNb: 20, + monday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_1', + 'CONF_1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_NIV2', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + }, + }, + { + name: 'core:PreviousTargetTemperatureState', + type: 2, + value: 17, + }, + { + name: 'core:TimeProgramState', + type: 10, + value: [ + { + monday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + tuesday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + wednesday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + thursday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + friday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + saturday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + sunday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + ], + }, + ], + attributes: [ + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + ], + available: true, + enabled: true, + placeOID: '2de0b602-9a42-48d3-9c9f-42bc192c8783', + place: 'Maxime', + widget: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + type: 1, + oid: '29bbe178-d3e3-4322-85dd-cafc8148cf41', + uiClass: 'HeatingSystem', + }, + '0a9055f2-6748-4f7b-b6f1-e396cc13203b': { + creationTime: 1586773220000, + lastUpdateTime: 1586773220000, + label: 'IO (6412161#2)', + deviceURL: 'io://0814-0291-7832/6412161#2', + shortcut: false, + controllableName: 'io:TemperatureInCelciusIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:TemperatureState', + }, + ], + dataProperties: [], + widgetName: 'TemperatureSensor', + uiProfiles: ['Temperature'], + uiClass: 'TemperatureSensor', + qualifiedName: 'io:TemperatureInCelciusIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:TemperatureState', + type: 2, + value: 16.33, + }, + ], + attributes: [ + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:MeasuredValueType', + type: 3, + value: 'core:TemperatureInCelcius', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + ], + available: true, + enabled: true, + placeOID: '2de0b602-9a42-48d3-9c9f-42bc192c8783', + place: 'Maxime', + widget: 'TemperatureSensor', + type: 2, + oid: '0a9055f2-6748-4f7b-b6f1-e396cc13203b', + uiClass: 'TemperatureSensor', + }, + '73a92bd3-b831-4071-b1ff-a5f6b55cc838': { + creationTime: 1586773220000, + lastUpdateTime: 1586773220000, + label: 'IO (6412161#3)', + deviceURL: 'io://0814-0291-7832/6412161#3', + shortcut: false, + controllableName: 'io:ContactIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + type: 'DiscreteState', + values: ['closed', 'open'], + qualifiedName: 'core:ContactState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + ], + dataProperties: [], + widgetName: 'ContactSensor', + uiProfiles: ['DoorContactSensor', 'ContactDetector'], + uiClass: 'ContactSensor', + qualifiedName: 'io:ContactIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:ContactState', + type: 3, + value: 'closed', + }, + ], + attributes: [ + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + ], + available: true, + enabled: true, + placeOID: '2de0b602-9a42-48d3-9c9f-42bc192c8783', + place: 'Maxime', + widget: 'ContactSensor', + type: 2, + oid: '73a92bd3-b831-4071-b1ff-a5f6b55cc838', + uiClass: 'ContactSensor', + }, + '357d8eb4-7bb5-45bf-a6ab-afa7460b673a': { + creationTime: 1586773220000, + lastUpdateTime: 1586773220000, + label: 'IO (6412161#4)', + deviceURL: 'io://0814-0291-7832/6412161#4', + shortcut: false, + controllableName: 'io:OccupancyIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + eventBased: true, + type: 'DiscreteState', + values: ['noPersonInside', 'personInside'], + qualifiedName: 'core:OccupancyState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + ], + dataProperties: [], + widgetName: 'OccupancySensor', + uiProfiles: ['OccupancyDetector'], + uiClass: 'OccupancySensor', + qualifiedName: 'io:OccupancyIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:OccupancyState', + type: 3, + value: 'noPersonInside', + }, + ], + attributes: [ + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + ], + available: true, + enabled: true, + placeOID: '2de0b602-9a42-48d3-9c9f-42bc192c8783', + place: 'Maxime', + widget: 'OccupancySensor', + type: 2, + oid: '357d8eb4-7bb5-45bf-a6ab-afa7460b673a', + uiClass: 'OccupancySensor', + }, + 'd4642883-14a9-4d05-ad6c-c50e3c1448e4': { + creationTime: 1586773220000, + lastUpdateTime: 1586773220000, + label: 'IO (6412161#5)', + deviceURL: 'io://0814-0291-7832/6412161#5', + shortcut: false, + controllableName: 'io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor', + definition: { + commands: [], + states: [ + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff0State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff1State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff2State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff3State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff4State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff5State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff6State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff7State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff8State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ConsumptionTariff9State', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:ElectricEnergyConsumptionState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + ], + dataProperties: [], + widgetName: 'CumulativeElectricPowerConsumptionSensor', + uiProfiles: ['ElectricEnergyConsumption'], + uiClass: 'ElectricitySensor', + qualifiedName: 'io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor', + type: 'SENSOR', + }, + states: [ + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:ElectricEnergyConsumptionState', + type: 1, + value: 146000, + }, + { + name: 'core:ConsumptionTariff1State', + type: 1, + value: 4000, + }, + { + name: 'core:ConsumptionTariff2State', + type: 1, + value: 58000, + }, + ], + attributes: [ + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:PowerSourceType', + type: 3, + value: 'mainSupply', + }, + { + name: 'core:MeasuredValueType', + type: 3, + value: 'core:ElectricalEnergyInWh', + }, + ], + available: true, + enabled: true, + placeOID: '2de0b602-9a42-48d3-9c9f-42bc192c8783', + place: 'Maxime', + widget: 'CumulativeElectricPowerConsumptionSensor', + type: 2, + oid: 'd4642883-14a9-4d05-ad6c-c50e3c1448e4', + uiClass: 'ElectricitySensor', + }, + }; + overkizHandler.connected = true; + const devices = await overkizHandler.getOverkizDevices(); + expect(devices).to.deep.equal([ + { + id: 'io://0814-0291-7832/11410052', + name: 'Radiateur (Salle de bain)', + model: 'AGILIA H PI-io 750W (Atlantic)', + service_id: 'OVERKIZ_SERVICE_ID', + external_id: 'overkiz:oid:fbb6f179-92b4-479a-9c53-41607e3c7a15', + updatable: true, + ready: true, + rawOverkizDevice: { + id: 'fbb6f179-92b4-479a-9c53-41607e3c7a15', + creationTime: 1601921868000, + lastUpdateTime: 1601921868000, + label: 'Radiateur', + deviceURL: 'io://0814-0291-7832/11410052#1', + shortcut: false, + controllableName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + definition: { + commands: [ + { + commandName: 'advancedRefresh', + nparams: 1, + }, + { + commandName: 'cancelHeatingLevel', + nparams: 1, + }, + { + commandName: 'delayedStopIdentify', + nparams: 1, + }, + { + commandName: 'getName', + nparams: 0, + }, + { + commandName: 'identify', + nparams: 0, + }, + { + commandName: 'noPersonInside', + nparams: 0, + }, + { + commandName: 'off', + nparams: 0, + }, + { + commandName: 'personInside', + nparams: 0, + }, + { + commandName: 'refreshComfortTemperature', + nparams: 0, + }, + { + commandName: 'refreshDateTime', + nparams: 0, + }, + { + commandName: 'refreshDerogatedTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshEcoTemperature', + nparams: 0, + }, + { + commandName: 'refreshHeatingLevel', + nparams: 0, + }, + { + commandName: 'refreshIdentifier', + nparams: 0, + }, + { + commandName: 'refreshManufacturerName', + nparams: 0, + }, + { + commandName: 'refreshMaximumHeatingTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshMaximumTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshOperatingMode', + nparams: 0, + }, + { + commandName: 'refreshTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshTemperature', + nparams: 0, + }, + { + commandName: 'refreshTimeProgram', + nparams: 0, + }, + { + commandName: 'setComfortTemperature', + nparams: 1, + }, + { + commandName: 'setDateTime', + nparams: 1, + }, + { + commandName: 'setDerogatedTargetTemperature', + nparams: 1, + }, + { + commandName: 'setEcoTemperature', + nparams: 1, + }, + { + commandName: 'setHeatingLevel', + nparams: 1, + }, + { + commandName: 'setHeatingLevelWithTimer', + nparams: 2, + }, + { + commandName: 'setHolidays', + nparams: 1, + }, + { + commandName: 'setHolidaysTargetTemperature', + nparams: 1, + }, + { + commandName: 'setName', + nparams: 1, + }, + { + commandName: 'setOccupancyActivation', + nparams: 1, + }, + { + commandName: 'setOccupancy', + nparams: 1, + }, + { + commandName: 'setOpenWindowDetectionActivation', + nparams: 1, + }, + { + commandName: 'setOperatingMode', + nparams: 1, + }, + { + commandName: 'setPreviousTargetTemperature', + nparams: 1, + }, + { + commandName: 'setSchedulingType', + nparams: 1, + }, + { + commandName: 'setTargetTemperature', + nparams: 1, + }, + { + commandName: 'setTimeProgram', + nparams: 1, + }, + { + commandName: 'startIdentify', + nparams: 0, + }, + { + commandName: 'stopIdentify', + nparams: 0, + }, + { + commandName: 'wink', + nparams: 1, + }, + { + commandName: 'pairOneWayController', + nparams: 2, + }, + { + commandName: 'refreshAutoProgram', + nparams: 0, + }, + { + commandName: 'refreshControllerAddress', + nparams: 0, + }, + { + commandName: 'refreshCumulatedLowering', + nparams: 0, + }, + { + commandName: 'refreshCurrentWorkingRate', + nparams: 0, + }, + { + commandName: 'refreshDeletionCancelation', + nparams: 0, + }, + { + commandName: 'refreshEffectiveTemperatureSetpoint', + nparams: 0, + }, + { + commandName: 'refreshLocalLeadTime', + nparams: 0, + }, + { + commandName: 'refreshModel', + nparams: 0, + }, + { + commandName: 'refreshNativeFunctionalLevel', + nparams: 0, + }, + { + commandName: 'refreshPeakNotice', + nparams: 0, + }, + { + commandName: 'refreshPeakWarning', + nparams: 0, + }, + { + commandName: 'refreshPowerAndTension', + nparams: 0, + }, + { + commandName: 'refreshRoomDeletionThreshold', + nparams: 0, + }, + { + commandName: 'refreshSetpointLoweringTemperatureInProgMode', + nparams: 0, + }, + { + commandName: 'refreshSynchronisationRequest', + nparams: 0, + }, + { + commandName: 'refreshTemperatureProbeCalibrationOffset', + nparams: 0, + }, + { + commandName: 'setCommunicationTest', + nparams: 1, + }, + { + commandName: 'setDeletionCancelation', + nparams: 1, + }, + { + commandName: 'setExpectedPresence', + nparams: 1, + }, + { + commandName: 'setHeatingLevelForTrigger', + nparams: 1, + }, + { + commandName: 'setNativeLevelsList', + nparams: 1, + }, + { + commandName: 'setPeakNotice', + nparams: 1, + }, + { + commandName: 'setPeakWarning', + nparams: 1, + }, + { + commandName: 'setRoomDeletionThreshold', + nparams: 1, + }, + { + commandName: 'setSetpointLoweringTemperatureInProgMode', + nparams: 1, + }, + { + commandName: 'setTemperatureProbeCalibrationOffset', + nparams: 1, + }, + { + commandName: 'setTwinningExit', + nparams: 1, + }, + { + commandName: 'unpairAllOneWayControllers', + nparams: 0, + }, + { + commandName: 'unpairOneWayController', + nparams: 2, + }, + ], + states: [ + { + type: 'ContinuousState', + qualifiedName: 'core:ComfortRoomTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:DateTimeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:DerogatedTargetTemperatureState', + }, + { + type: 'DiscreteState', + values: ['good', 'low', 'normal', 'verylow'], + qualifiedName: 'core:DiscreteRSSILevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:EcoRoomTemperatureState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:HolidaysModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:HolidaysTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:IdentifierState', + }, + { + type: 'DataState', + qualifiedName: 'core:ManufacturerNameState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumHeatingTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:NameState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OccupancyActivationState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:OnOffState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OpenWindowDetectionActivationState', + }, + { + type: 'DiscreteState', + values: [ + 'antifreeze', + 'auto', + 'away', + 'eco', + 'frostprotection', + 'manual', + 'max', + 'normal', + 'off', + 'on', + 'prog', + 'program', + 'boost', + ], + qualifiedName: 'core:OperatingModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PreviousTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PriorityLockTimerState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:RSSILevelState', + }, + { + type: 'DiscreteState', + values: ['increase', 'none', 'standby'], + qualifiedName: 'core:RegulationModeState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:TargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:TimeProgramState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:VersionState', + }, + { + type: 'DataState', + qualifiedName: 'io:AutoProgramState', + }, + { + type: 'DataState', + qualifiedName: 'io:ControllerAddressState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CumulatedLoweringState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CurrentWorkingRateState', + }, + { + type: 'DiscreteState', + values: ['deletion cancelation', 'no deletion cancelation'], + qualifiedName: 'io:DeletionCancelationState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:EffectiveTemperatureSetpointState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:ExpectedPresenceState', + }, + { + type: 'DiscreteState', + values: ['external', 'internal'], + qualifiedName: 'io:InternalExternalSchedulingTypeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:LocalLeadTimeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:MaximumHeatingLevelState', + }, + { + type: 'DataState', + qualifiedName: 'io:ModelState', + }, + { + type: 'DiscreteState', + values: ['base', 'medium', 'top'], + qualifiedName: 'io:NativeFunctionalLevelState', + }, + { + type: 'DiscreteState', + values: ['long peak', 'no peak', 'short peak'], + qualifiedName: 'io:PeakNoticeState', + }, + { + type: 'DiscreteState', + values: ['long peak warning', 'no warning', 'short peak warning'], + qualifiedName: 'io:PeakWarningState', + }, + { + type: 'DataState', + qualifiedName: 'io:PowerState', + }, + { + type: 'DiscreteState', + values: [ + 'comfortLevel1', + 'comfortLevel2', + 'comfortLevel3', + 'comfortLevel4', + 'environmentProtection', + 'humanProtection', + 'userLevel1', + 'userLevel2', + ], + qualifiedName: 'io:PriorityLockLevelState', + }, + { + type: 'DiscreteState', + values: [ + 'LSC', + 'SAAC', + 'SFC', + 'UPS', + 'externalGateway', + 'localUser', + 'myself', + 'rain', + 'security', + 'temperature', + 'timer', + 'user', + 'wind', + ], + qualifiedName: 'io:PriorityLockOriginatorState', + }, + { + type: 'DataState', + qualifiedName: 'io:RoomDeletionThresholdState', + }, + { + type: 'DiscreteState', + values: ['kept', 'lost'], + qualifiedName: 'io:RunningState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:SetpointLoweringTemperatureInProgModeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:TargetHeatingLevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TemperatureProbeCalibrationOffsetState', + }, + { + type: 'DataState', + qualifiedName: 'io:TensionState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TimerForTransitoryStateState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:UptimeState', + }, + ], + dataProperties: [ + { + value: '500', + qualifiedName: 'core:identifyInterval', + }, + ], + widgetName: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + uiProfiles: ['StatefulOperatingModeHeating', 'OperatingModeHeating', 'StatefulThermostat', 'Thermostat'], + uiClass: 'HeatingSystem', + uiClassifiers: ['emitter'], + qualifiedName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + type: 'ACTUATOR', + }, + states: [ + { + name: 'core:NameState', + type: 3, + value: 'Radiateur', + }, + { + name: 'core:VersionState', + type: 3, + value: '49373431303038202020', + }, + { + name: 'core:PriorityLockTimerState', + type: 1, + value: 0, + }, + { + name: 'core:OnOffState', + type: 3, + value: 'on', + }, + { + name: 'io:TargetHeatingLevelState', + type: 3, + value: 'eco', + }, + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:DiscreteRSSILevelState', + type: 3, + value: 'normal', + }, + { + name: 'core:RSSILevelState', + type: 2, + value: 56, + }, + { + name: 'core:IdentifierState', + type: 3, + value: '00000000', + }, + { + name: 'io:MaximumHeatingLevelState', + type: 3, + value: 'unknown', + }, + { + name: 'io:TimerForTransitoryStateState', + type: 1, + value: 0, + }, + { + name: 'core:ComfortRoomTemperatureState', + type: 1, + value: 18, + }, + { + name: 'core:EcoRoomTemperatureState', + type: 1, + value: 7, + }, + { + name: 'core:OperatingModeState', + type: 3, + value: 'internal', + }, + { + name: 'core:OccupancyActivationState', + type: 3, + value: 'inactive', + }, + { + name: 'core:MaximumHeatingTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:MaximumTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:TargetTemperatureState', + type: 2, + value: 18, + }, + { + name: 'io:SetpointLoweringTemperatureInProgModeState', + type: 2, + value: 7, + }, + { + name: 'core:OpenWindowDetectionActivationState', + type: 3, + value: 'active', + }, + { + name: 'io:InternalExternalSchedulingTypeState', + type: 3, + value: 'internal', + }, + { + name: 'core:DateTimeState', + type: 11, + value: { + month: 3, + hour: 9, + year: 2018, + weekday: 5, + day: 10, + minute: 40, + second: 50, + }, + }, + { + name: 'io:LocalLeadTimeState', + type: 1, + value: 2269, + }, + { + name: 'core:RegulationModeState', + type: 3, + value: 'none', + }, + { + name: 'core:ManufacturerNameState', + type: 3, + value: 'Atlantic', + }, + { + name: 'io:ModelState', + type: 3, + value: 'AGILIA H PI-io', + }, + { + name: 'io:PowerState', + type: 1, + value: 750, + }, + { + name: 'io:TensionState', + type: 1, + value: 230, + }, + { + name: 'core:DerogatedTargetTemperatureState', + type: 2, + value: 0, + }, + { + name: 'io:NativeFunctionalLevelState', + type: 3, + value: 'Top', + }, + { + name: 'io:TemperatureProbeCalibrationOffsetState', + type: 2, + value: 0, + }, + { + name: 'io:CurrentWorkingRateState', + type: 2, + value: 0, + }, + { + name: 'io:CumulatedLoweringState', + type: 2, + value: 0, + }, + { + name: 'io:RoomDeletionThresholdState', + type: 3, + value: '-2°C', + }, + { + name: 'io:EffectiveTemperatureSetpointState', + type: 2, + value: 11, + }, + { + name: 'io:ControllerAddressState', + type: 1, + value: 11410051, + }, + { + name: 'io:ExpectedPresenceState', + type: 3, + value: '17:30', + lastUpdateTime: 1607184038000, + }, + { + name: 'io:AutoProgramState', + type: 11, + value: { + sunday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_NIV3', + 'CONF_2', + 'CONF_1', + 'CONF_2', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_2', + 'CONF_NIV2', + 'CONF_NIV1', + 'CONF_2', + 'CONF_NIV2', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_1', + 'CONF_1', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_2', + 'CONF_1', + 'CONF_1', + 'CONF_3_NIV2', + ], + saturday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_NIV1', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + ], + tuesday: [ + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_NIV3', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV2', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_1', + 'CONF_1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_NIV1', + 'CONF_NIV3', + 'CONF_1', + 'CONF_2', + 'CONF_2', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_1', + 'CONF_NIV1', + 'CONF_2', + 'CONF_NIV2', + 'CONF_3_NIV1', + ], + wednesday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV1', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_2', + 'CONF_1', + 'CONF_1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV2', + ], + thursday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_2', + 'CONF_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_NIV2', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + ], + friday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_2', + 'CONF_NIV3', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_NIV1', + 'CONF_2', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_NIV1', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_2', + 'CONF_NIV2', + 'CONF_1', + 'CONF_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV2', + ], + anticipTime: 2269, + anticipNb: 20, + monday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_1', + 'CONF_2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_NIV3', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + }, + }, + { + name: 'core:TimeProgramState', + type: 10, + value: [ + { + monday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + tuesday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + wednesday: [ + { + start: '06:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + thursday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + friday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + saturday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + sunday: [ + { + start: '05:30', + end: '08:30', + }, + { + start: '18:30', + end: '21:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + ], + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + ], + available: true, + enabled: true, + placeOID: '9abb0634-9b62-476f-8a60-0a63463e011b', + place: 'Salle de bain', + widget: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + type: 1, + oid: 'fbb6f179-92b4-479a-9c53-41607e3c7a15', + uiClass: 'HeatingSystem', + }, + features: [ + { + name: 'Temperature', + selector: 'overkiz-45eca6ef-5a88-4858-a84c-f9614258f966-temperaturesensor', + category: 'temperature-sensor', + type: 'decimal', + external_id: 'overkiz-45eca6ef-5a88-4858-a84c-f9614258f966-TemperatureSensor', + read_only: true, + unit: 'celsius', + has_feedback: true, + min: 0, + max: 40, + }, + { + name: 'Occupancy', + selector: 'overkiz-2263edf8-95b5-41e8-8c59-a44c89aabe6f-occupancysensor', + category: 'presence-sensor', + type: 'push', + external_id: 'overkiz-2263edf8-95b5-41e8-8c59-a44c89aabe6f-OccupancySensor', + read_only: true, + has_feedback: false, + keep_history: true, + min: 0, + max: 1, + }, + ], + params: [ + { + name: 'ONLINE', + value: 'available', + }, + { + name: 'FIRMWARE', + value: 'I741008', + }, + ], + }, + { + id: 'io://0814-0291-7832/5276217', + name: 'Radiateur (Parents)', + model: 'AGILIA H PI-io 750W (Atlantic)', + service_id: 'OVERKIZ_SERVICE_ID', + external_id: 'overkiz:oid:f2ca7610-248c-46a8-bf34-41edea559df5', + updatable: true, + ready: true, + rawOverkizDevice: { + id: 'f2ca7610-248c-46a8-bf34-41edea559df5', + creationTime: 1588332894000, + lastUpdateTime: 1588332894000, + label: 'Radiateur', + deviceURL: 'io://0814-0291-7832/5276217#1', + shortcut: false, + controllableName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + definition: { + commands: [ + { + commandName: 'advancedRefresh', + nparams: 1, + }, + { + commandName: 'cancelHeatingLevel', + nparams: 1, + }, + { + commandName: 'delayedStopIdentify', + nparams: 1, + }, + { + commandName: 'getName', + nparams: 0, + }, + { + commandName: 'identify', + nparams: 0, + }, + { + commandName: 'noPersonInside', + nparams: 0, + }, + { + commandName: 'off', + nparams: 0, + }, + { + commandName: 'personInside', + nparams: 0, + }, + { + commandName: 'refreshComfortTemperature', + nparams: 0, + }, + { + commandName: 'refreshDateTime', + nparams: 0, + }, + { + commandName: 'refreshDerogatedTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshEcoTemperature', + nparams: 0, + }, + { + commandName: 'refreshHeatingLevel', + nparams: 0, + }, + { + commandName: 'refreshIdentifier', + nparams: 0, + }, + { + commandName: 'refreshManufacturerName', + nparams: 0, + }, + { + commandName: 'refreshMaximumHeatingTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshMaximumTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshOperatingMode', + nparams: 0, + }, + { + commandName: 'refreshTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshTemperature', + nparams: 0, + }, + { + commandName: 'refreshTimeProgram', + nparams: 0, + }, + { + commandName: 'setComfortTemperature', + nparams: 1, + }, + { + commandName: 'setDateTime', + nparams: 1, + }, + { + commandName: 'setDerogatedTargetTemperature', + nparams: 1, + }, + { + commandName: 'setEcoTemperature', + nparams: 1, + }, + { + commandName: 'setHeatingLevel', + nparams: 1, + }, + { + commandName: 'setHeatingLevelWithTimer', + nparams: 2, + }, + { + commandName: 'setHolidays', + nparams: 1, + }, + { + commandName: 'setHolidaysTargetTemperature', + nparams: 1, + }, + { + commandName: 'setName', + nparams: 1, + }, + { + commandName: 'setOccupancyActivation', + nparams: 1, + }, + { + commandName: 'setOccupancy', + nparams: 1, + }, + { + commandName: 'setOpenWindowDetectionActivation', + nparams: 1, + }, + { + commandName: 'setOperatingMode', + nparams: 1, + }, + { + commandName: 'setPreviousTargetTemperature', + nparams: 1, + }, + { + commandName: 'setSchedulingType', + nparams: 1, + }, + { + commandName: 'setTargetTemperature', + nparams: 1, + }, + { + commandName: 'setTimeProgram', + nparams: 1, + }, + { + commandName: 'startIdentify', + nparams: 0, + }, + { + commandName: 'stopIdentify', + nparams: 0, + }, + { + commandName: 'wink', + nparams: 1, + }, + { + commandName: 'pairOneWayController', + nparams: 2, + }, + { + commandName: 'refreshAutoProgram', + nparams: 0, + }, + { + commandName: 'refreshControllerAddress', + nparams: 0, + }, + { + commandName: 'refreshCumulatedLowering', + nparams: 0, + }, + { + commandName: 'refreshCurrentWorkingRate', + nparams: 0, + }, + { + commandName: 'refreshDeletionCancelation', + nparams: 0, + }, + { + commandName: 'refreshEffectiveTemperatureSetpoint', + nparams: 0, + }, + { + commandName: 'refreshLocalLeadTime', + nparams: 0, + }, + { + commandName: 'refreshModel', + nparams: 0, + }, + { + commandName: 'refreshNativeFunctionalLevel', + nparams: 0, + }, + { + commandName: 'refreshPeakNotice', + nparams: 0, + }, + { + commandName: 'refreshPeakWarning', + nparams: 0, + }, + { + commandName: 'refreshPowerAndTension', + nparams: 0, + }, + { + commandName: 'refreshRoomDeletionThreshold', + nparams: 0, + }, + { + commandName: 'refreshSetpointLoweringTemperatureInProgMode', + nparams: 0, + }, + { + commandName: 'refreshSynchronisationRequest', + nparams: 0, + }, + { + commandName: 'refreshTemperatureProbeCalibrationOffset', + nparams: 0, + }, + { + commandName: 'setCommunicationTest', + nparams: 1, + }, + { + commandName: 'setDeletionCancelation', + nparams: 1, + }, + { + commandName: 'setExpectedPresence', + nparams: 1, + }, + { + commandName: 'setHeatingLevelForTrigger', + nparams: 1, + }, + { + commandName: 'setNativeLevelsList', + nparams: 1, + }, + { + commandName: 'setPeakNotice', + nparams: 1, + }, + { + commandName: 'setPeakWarning', + nparams: 1, + }, + { + commandName: 'setRoomDeletionThreshold', + nparams: 1, + }, + { + commandName: 'setSetpointLoweringTemperatureInProgMode', + nparams: 1, + }, + { + commandName: 'setTemperatureProbeCalibrationOffset', + nparams: 1, + }, + { + commandName: 'setTwinningExit', + nparams: 1, + }, + { + commandName: 'unpairAllOneWayControllers', + nparams: 0, + }, + { + commandName: 'unpairOneWayController', + nparams: 2, + }, + ], + states: [ + { + type: 'ContinuousState', + qualifiedName: 'core:ComfortRoomTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:DateTimeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:DerogatedTargetTemperatureState', + }, + { + type: 'DiscreteState', + values: ['good', 'low', 'normal', 'verylow'], + qualifiedName: 'core:DiscreteRSSILevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:EcoRoomTemperatureState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:HolidaysModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:HolidaysTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:IdentifierState', + }, + { + type: 'DataState', + qualifiedName: 'core:ManufacturerNameState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumHeatingTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:NameState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OccupancyActivationState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:OnOffState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OpenWindowDetectionActivationState', + }, + { + type: 'DiscreteState', + values: [ + 'antifreeze', + 'auto', + 'away', + 'eco', + 'frostprotection', + 'manual', + 'max', + 'normal', + 'off', + 'on', + 'prog', + 'program', + 'boost', + ], + qualifiedName: 'core:OperatingModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PreviousTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PriorityLockTimerState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:RSSILevelState', + }, + { + type: 'DiscreteState', + values: ['increase', 'none', 'standby'], + qualifiedName: 'core:RegulationModeState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:TargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:TimeProgramState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:VersionState', + }, + { + type: 'DataState', + qualifiedName: 'io:AutoProgramState', + }, + { + type: 'DataState', + qualifiedName: 'io:ControllerAddressState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CumulatedLoweringState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CurrentWorkingRateState', + }, + { + type: 'DiscreteState', + values: ['deletion cancelation', 'no deletion cancelation'], + qualifiedName: 'io:DeletionCancelationState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:EffectiveTemperatureSetpointState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:ExpectedPresenceState', + }, + { + type: 'DiscreteState', + values: ['external', 'internal'], + qualifiedName: 'io:InternalExternalSchedulingTypeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:LocalLeadTimeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:MaximumHeatingLevelState', + }, + { + type: 'DataState', + qualifiedName: 'io:ModelState', + }, + { + type: 'DiscreteState', + values: ['base', 'medium', 'top'], + qualifiedName: 'io:NativeFunctionalLevelState', + }, + { + type: 'DiscreteState', + values: ['long peak', 'no peak', 'short peak'], + qualifiedName: 'io:PeakNoticeState', + }, + { + type: 'DiscreteState', + values: ['long peak warning', 'no warning', 'short peak warning'], + qualifiedName: 'io:PeakWarningState', + }, + { + type: 'DataState', + qualifiedName: 'io:PowerState', + }, + { + type: 'DiscreteState', + values: [ + 'comfortLevel1', + 'comfortLevel2', + 'comfortLevel3', + 'comfortLevel4', + 'environmentProtection', + 'humanProtection', + 'userLevel1', + 'userLevel2', + ], + qualifiedName: 'io:PriorityLockLevelState', + }, + { + type: 'DiscreteState', + values: [ + 'LSC', + 'SAAC', + 'SFC', + 'UPS', + 'externalGateway', + 'localUser', + 'myself', + 'rain', + 'security', + 'temperature', + 'timer', + 'user', + 'wind', + ], + qualifiedName: 'io:PriorityLockOriginatorState', + }, + { + type: 'DataState', + qualifiedName: 'io:RoomDeletionThresholdState', + }, + { + type: 'DiscreteState', + values: ['kept', 'lost'], + qualifiedName: 'io:RunningState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:SetpointLoweringTemperatureInProgModeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:TargetHeatingLevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TemperatureProbeCalibrationOffsetState', + }, + { + type: 'DataState', + qualifiedName: 'io:TensionState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TimerForTransitoryStateState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:UptimeState', + }, + ], + dataProperties: [ + { + value: '500', + qualifiedName: 'core:identifyInterval', + }, + ], + widgetName: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + uiProfiles: ['StatefulOperatingModeHeating', 'OperatingModeHeating', 'StatefulThermostat', 'Thermostat'], + uiClass: 'HeatingSystem', + uiClassifiers: ['emitter'], + qualifiedName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + type: 'ACTUATOR', + }, + states: [ + { + name: 'core:NameState', + type: 3, + value: 'Radiateur', + }, + { + name: 'core:VersionState', + type: 3, + value: '49373431303038202020', + }, + { + name: 'core:PriorityLockTimerState', + type: 1, + value: 0, + }, + { + name: 'core:OnOffState', + type: 3, + value: 'on', + }, + { + name: 'io:TargetHeatingLevelState', + type: 3, + value: 'comfort', + }, + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:DiscreteRSSILevelState', + type: 3, + value: 'normal', + }, + { + name: 'core:RSSILevelState', + type: 2, + value: 66, + }, + { + name: 'core:IdentifierState', + type: 3, + value: '00000000', + }, + { + name: 'io:MaximumHeatingLevelState', + type: 3, + value: 'unknown', + }, + { + name: 'io:TimerForTransitoryStateState', + type: 1, + value: 0, + }, + { + name: 'core:ComfortRoomTemperatureState', + type: 1, + value: 14, + }, + { + name: 'core:EcoRoomTemperatureState', + type: 1, + value: 4, + }, + { + name: 'core:OperatingModeState', + type: 3, + value: 'auto', + }, + { + name: 'core:OccupancyActivationState', + type: 3, + value: 'active', + }, + { + name: 'core:MaximumHeatingTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:MaximumTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:TargetTemperatureState', + type: 2, + value: 14, + }, + { + name: 'io:SetpointLoweringTemperatureInProgModeState', + type: 2, + value: 4, + }, + { + name: 'core:OpenWindowDetectionActivationState', + type: 3, + value: 'active', + }, + { + name: 'io:InternalExternalSchedulingTypeState', + type: 3, + value: 'internal', + }, + { + name: 'core:DateTimeState', + type: 11, + value: { + month: 3, + hour: 9, + year: 2018, + weekday: 5, + day: 10, + minute: 40, + second: 14, + }, + }, + { + name: 'io:LocalLeadTimeState', + type: 1, + value: 1737, + }, + { + name: 'core:RegulationModeState', + type: 3, + value: 'none', + }, + { + name: 'core:ManufacturerNameState', + type: 3, + value: 'Atlantic', + }, + { + name: 'io:ModelState', + type: 3, + value: 'AGILIA H PI-io', + }, + { + name: 'io:PowerState', + type: 1, + value: 750, + }, + { + name: 'io:TensionState', + type: 1, + value: 230, + }, + { + name: 'core:DerogatedTargetTemperatureState', + type: 2, + value: 0, + }, + { + name: 'io:NativeFunctionalLevelState', + type: 3, + value: 'Top', + }, + { + name: 'io:TemperatureProbeCalibrationOffsetState', + type: 2, + value: 0, + }, + { + name: 'io:CurrentWorkingRateState', + type: 2, + value: 0, + }, + { + name: 'io:CumulatedLoweringState', + type: 2, + value: 91, + }, + { + name: 'io:RoomDeletionThresholdState', + type: 3, + value: '-2°C', + }, + { + name: 'io:EffectiveTemperatureSetpointState', + type: 2, + value: 14, + }, + { + name: 'io:ControllerAddressState', + type: 1, + value: 5276216, + }, + { + name: 'io:ExpectedPresenceState', + type: 3, + value: '19:30', + lastUpdateTime: 1607019810000, + }, + { + name: 'io:AutoProgramState', + type: 11, + value: { + sunday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + saturday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + tuesday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + wednesday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + ], + thursday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + ], + friday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + ], + anticipTime: 1737, + anticipNb: 20, + monday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + }, + }, + { + name: 'core:PreviousTargetTemperatureState', + type: 2, + value: 18, + }, + { + name: 'core:TimeProgramState', + type: 10, + value: [ + { + monday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + tuesday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + wednesday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + thursday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + friday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + saturday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + sunday: [ + { + start: '07:00', + end: '08:00', + }, + { + start: '18:30', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + ], + }, + ], + attributes: [ + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + ], + available: true, + enabled: true, + placeOID: 'dab51ec0-5b0c-4694-8389-7498f02d6ee6', + place: 'Parents', + widget: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + type: 1, + oid: 'f2ca7610-248c-46a8-bf34-41edea559df5', + uiClass: 'HeatingSystem', + }, + features: [ + { + name: 'Temperature', + selector: 'overkiz-b8ea4ea5-9eb2-4d79-989b-1c73eeb5e458-temperaturesensor', + category: 'temperature-sensor', + type: 'decimal', + external_id: 'overkiz-b8ea4ea5-9eb2-4d79-989b-1c73eeb5e458-TemperatureSensor', + read_only: true, + unit: 'celsius', + has_feedback: true, + min: 0, + max: 40, + }, + { + name: 'Occupancy', + selector: 'overkiz-4a2301c2-3793-47eb-b7d9-ea73b7172f2e-occupancysensor', + category: 'presence-sensor', + type: 'push', + external_id: 'overkiz-4a2301c2-3793-47eb-b7d9-ea73b7172f2e-OccupancySensor', + read_only: true, + has_feedback: false, + keep_history: true, + min: 0, + max: 1, + }, + ], + params: [ + { + name: 'ONLINE', + value: 'available', + }, + { + name: 'FIRMWARE', + value: 'I741008', + }, + ], + }, + { + id: 'io://0814-0291-7832/6412161', + name: 'Radiateur (Maxime)', + model: 'AGILIA H PI-io 750W (Atlantic)', + service_id: 'OVERKIZ_SERVICE_ID', + external_id: 'overkiz:oid:29bbe178-d3e3-4322-85dd-cafc8148cf41', + updatable: true, + ready: true, + rawOverkizDevice: { + id: '29bbe178-d3e3-4322-85dd-cafc8148cf41', + creationTime: 1586773220000, + lastUpdateTime: 1586773220000, + label: 'Radiateur', + deviceURL: 'io://0814-0291-7832/6412161#1', + shortcut: false, + controllableName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + definition: { + commands: [ + { + commandName: 'advancedRefresh', + nparams: 1, + }, + { + commandName: 'cancelHeatingLevel', + nparams: 1, + }, + { + commandName: 'delayedStopIdentify', + nparams: 1, + }, + { + commandName: 'getName', + nparams: 0, + }, + { + commandName: 'identify', + nparams: 0, + }, + { + commandName: 'noPersonInside', + nparams: 0, + }, + { + commandName: 'off', + nparams: 0, + }, + { + commandName: 'personInside', + nparams: 0, + }, + { + commandName: 'refreshComfortTemperature', + nparams: 0, + }, + { + commandName: 'refreshDateTime', + nparams: 0, + }, + { + commandName: 'refreshDerogatedTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshEcoTemperature', + nparams: 0, + }, + { + commandName: 'refreshHeatingLevel', + nparams: 0, + }, + { + commandName: 'refreshIdentifier', + nparams: 0, + }, + { + commandName: 'refreshManufacturerName', + nparams: 0, + }, + { + commandName: 'refreshMaximumHeatingTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshMaximumTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshOperatingMode', + nparams: 0, + }, + { + commandName: 'refreshTargetTemperature', + nparams: 0, + }, + { + commandName: 'refreshTemperature', + nparams: 0, + }, + { + commandName: 'refreshTimeProgram', + nparams: 0, + }, + { + commandName: 'setComfortTemperature', + nparams: 1, + }, + { + commandName: 'setDateTime', + nparams: 1, + }, + { + commandName: 'setDerogatedTargetTemperature', + nparams: 1, + }, + { + commandName: 'setEcoTemperature', + nparams: 1, + }, + { + commandName: 'setHeatingLevel', + nparams: 1, + }, + { + commandName: 'setHeatingLevelWithTimer', + nparams: 2, + }, + { + commandName: 'setHolidays', + nparams: 1, + }, + { + commandName: 'setHolidaysTargetTemperature', + nparams: 1, + }, + { + commandName: 'setName', + nparams: 1, + }, + { + commandName: 'setOccupancyActivation', + nparams: 1, + }, + { + commandName: 'setOccupancy', + nparams: 1, + }, + { + commandName: 'setOpenWindowDetectionActivation', + nparams: 1, + }, + { + commandName: 'setOperatingMode', + nparams: 1, + }, + { + commandName: 'setPreviousTargetTemperature', + nparams: 1, + }, + { + commandName: 'setSchedulingType', + nparams: 1, + }, + { + commandName: 'setTargetTemperature', + nparams: 1, + }, + { + commandName: 'setTimeProgram', + nparams: 1, + }, + { + commandName: 'startIdentify', + nparams: 0, + }, + { + commandName: 'stopIdentify', + nparams: 0, + }, + { + commandName: 'wink', + nparams: 1, + }, + { + commandName: 'pairOneWayController', + nparams: 2, + }, + { + commandName: 'refreshAutoProgram', + nparams: 0, + }, + { + commandName: 'refreshControllerAddress', + nparams: 0, + }, + { + commandName: 'refreshCumulatedLowering', + nparams: 0, + }, + { + commandName: 'refreshCurrentWorkingRate', + nparams: 0, + }, + { + commandName: 'refreshDeletionCancelation', + nparams: 0, + }, + { + commandName: 'refreshEffectiveTemperatureSetpoint', + nparams: 0, + }, + { + commandName: 'refreshLocalLeadTime', + nparams: 0, + }, + { + commandName: 'refreshModel', + nparams: 0, + }, + { + commandName: 'refreshNativeFunctionalLevel', + nparams: 0, + }, + { + commandName: 'refreshPeakNotice', + nparams: 0, + }, + { + commandName: 'refreshPeakWarning', + nparams: 0, + }, + { + commandName: 'refreshPowerAndTension', + nparams: 0, + }, + { + commandName: 'refreshRoomDeletionThreshold', + nparams: 0, + }, + { + commandName: 'refreshSetpointLoweringTemperatureInProgMode', + nparams: 0, + }, + { + commandName: 'refreshSynchronisationRequest', + nparams: 0, + }, + { + commandName: 'refreshTemperatureProbeCalibrationOffset', + nparams: 0, + }, + { + commandName: 'setCommunicationTest', + nparams: 1, + }, + { + commandName: 'setDeletionCancelation', + nparams: 1, + }, + { + commandName: 'setExpectedPresence', + nparams: 1, + }, + { + commandName: 'setHeatingLevelForTrigger', + nparams: 1, + }, + { + commandName: 'setNativeLevelsList', + nparams: 1, + }, + { + commandName: 'setPeakNotice', + nparams: 1, + }, + { + commandName: 'setPeakWarning', + nparams: 1, + }, + { + commandName: 'setRoomDeletionThreshold', + nparams: 1, + }, + { + commandName: 'setSetpointLoweringTemperatureInProgMode', + nparams: 1, + }, + { + commandName: 'setTemperatureProbeCalibrationOffset', + nparams: 1, + }, + { + commandName: 'setTwinningExit', + nparams: 1, + }, + { + commandName: 'unpairAllOneWayControllers', + nparams: 0, + }, + { + commandName: 'unpairOneWayController', + nparams: 2, + }, + ], + states: [ + { + type: 'ContinuousState', + qualifiedName: 'core:ComfortRoomTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:DateTimeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:DerogatedTargetTemperatureState', + }, + { + type: 'DiscreteState', + values: ['good', 'low', 'normal', 'verylow'], + qualifiedName: 'core:DiscreteRSSILevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:EcoRoomTemperatureState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:HolidaysModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:HolidaysTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:IdentifierState', + }, + { + type: 'DataState', + qualifiedName: 'core:ManufacturerNameState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumHeatingTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:MaximumTargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:NameState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OccupancyActivationState', + }, + { + type: 'DiscreteState', + values: ['off', 'on'], + qualifiedName: 'core:OnOffState', + }, + { + type: 'DiscreteState', + values: ['active', 'inactive'], + qualifiedName: 'core:OpenWindowDetectionActivationState', + }, + { + type: 'DiscreteState', + values: [ + 'antifreeze', + 'auto', + 'away', + 'eco', + 'frostprotection', + 'manual', + 'max', + 'normal', + 'off', + 'on', + 'prog', + 'program', + 'boost', + ], + qualifiedName: 'core:OperatingModeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PreviousTargetTemperatureState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:PriorityLockTimerState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:RSSILevelState', + }, + { + type: 'DiscreteState', + values: ['increase', 'none', 'standby'], + qualifiedName: 'core:RegulationModeState', + }, + { + type: 'DiscreteState', + values: ['available', 'unavailable'], + qualifiedName: 'core:StatusState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:TargetTemperatureState', + }, + { + type: 'DataState', + qualifiedName: 'core:TimeProgramState', + }, + { + type: 'ContinuousState', + qualifiedName: 'core:VersionState', + }, + { + type: 'DataState', + qualifiedName: 'io:AutoProgramState', + }, + { + type: 'DataState', + qualifiedName: 'io:ControllerAddressState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CumulatedLoweringState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:CurrentWorkingRateState', + }, + { + type: 'DiscreteState', + values: ['deletion cancelation', 'no deletion cancelation'], + qualifiedName: 'io:DeletionCancelationState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:EffectiveTemperatureSetpointState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:ExpectedPresenceState', + }, + { + type: 'DiscreteState', + values: ['external', 'internal'], + qualifiedName: 'io:InternalExternalSchedulingTypeState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:LocalLeadTimeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:MaximumHeatingLevelState', + }, + { + type: 'DataState', + qualifiedName: 'io:ModelState', + }, + { + type: 'DiscreteState', + values: ['base', 'medium', 'top'], + qualifiedName: 'io:NativeFunctionalLevelState', + }, + { + type: 'DiscreteState', + values: ['long peak', 'no peak', 'short peak'], + qualifiedName: 'io:PeakNoticeState', + }, + { + type: 'DiscreteState', + values: ['long peak warning', 'no warning', 'short peak warning'], + qualifiedName: 'io:PeakWarningState', + }, + { + type: 'DataState', + qualifiedName: 'io:PowerState', + }, + { + type: 'DiscreteState', + values: [ + 'comfortLevel1', + 'comfortLevel2', + 'comfortLevel3', + 'comfortLevel4', + 'environmentProtection', + 'humanProtection', + 'userLevel1', + 'userLevel2', + ], + qualifiedName: 'io:PriorityLockLevelState', + }, + { + type: 'DiscreteState', + values: [ + 'LSC', + 'SAAC', + 'SFC', + 'UPS', + 'externalGateway', + 'localUser', + 'myself', + 'rain', + 'security', + 'temperature', + 'timer', + 'user', + 'wind', + ], + qualifiedName: 'io:PriorityLockOriginatorState', + }, + { + type: 'DataState', + qualifiedName: 'io:RoomDeletionThresholdState', + }, + { + type: 'DiscreteState', + values: ['kept', 'lost'], + qualifiedName: 'io:RunningState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:SetpointLoweringTemperatureInProgModeState', + }, + { + type: 'DiscreteState', + values: ['boost', 'comfort', 'comfort-1', 'comfort-2', 'eco', 'frostprotection', 'off', 'secured'], + qualifiedName: 'io:TargetHeatingLevelState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TemperatureProbeCalibrationOffsetState', + }, + { + type: 'DataState', + qualifiedName: 'io:TensionState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:TimerForTransitoryStateState', + }, + { + type: 'ContinuousState', + qualifiedName: 'io:UptimeState', + }, + ], + dataProperties: [ + { + value: '500', + qualifiedName: 'core:identifyInterval', + }, + ], + widgetName: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + uiProfiles: ['StatefulOperatingModeHeating', 'OperatingModeHeating', 'StatefulThermostat', 'Thermostat'], + uiClass: 'HeatingSystem', + uiClassifiers: ['emitter'], + qualifiedName: 'io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent', + type: 'ACTUATOR', + }, + states: [ + { + name: 'core:NameState', + type: 3, + value: 'Radiateur', + }, + { + name: 'core:VersionState', + type: 3, + value: '49373431303038202020', + }, + { + name: 'core:PriorityLockTimerState', + type: 1, + value: 0, + }, + { + name: 'core:OnOffState', + type: 3, + value: 'on', + }, + { + name: 'io:TargetHeatingLevelState', + type: 3, + value: 'comfort', + }, + { + name: 'core:StatusState', + type: 3, + value: 'available', + }, + { + name: 'core:DiscreteRSSILevelState', + type: 3, + value: 'normal', + }, + { + name: 'core:RSSILevelState', + type: 2, + value: 78, + }, + { + name: 'core:IdentifierState', + type: 3, + value: '00000000', + }, + { + name: 'io:MaximumHeatingLevelState', + type: 3, + value: 'unknown', + }, + { + name: 'io:TimerForTransitoryStateState', + type: 1, + value: 0, + }, + { + name: 'core:ComfortRoomTemperatureState', + type: 1, + value: 16, + }, + { + name: 'core:EcoRoomTemperatureState', + type: 2, + value: 4.5, + }, + { + name: 'core:OperatingModeState', + type: 3, + value: 'auto', + }, + { + name: 'core:OccupancyActivationState', + type: 3, + value: 'inactive', + }, + { + name: 'core:MaximumHeatingTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:MaximumTargetTemperatureState', + type: 2, + value: 28, + }, + { + name: 'core:TargetTemperatureState', + type: 2, + value: 16, + }, + { + name: 'io:SetpointLoweringTemperatureInProgModeState', + type: 2, + value: 4.5, + }, + { + name: 'core:OpenWindowDetectionActivationState', + type: 3, + value: 'inactive', + }, + { + name: 'io:InternalExternalSchedulingTypeState', + type: 3, + value: 'internal', + }, + { + name: 'core:DateTimeState', + type: 11, + value: { + month: 3, + hour: 9, + year: 2018, + weekday: 5, + day: 10, + minute: 40, + second: 47, + }, + }, + { + name: 'io:LocalLeadTimeState', + type: 1, + value: 1598, + }, + { + name: 'core:RegulationModeState', + type: 3, + value: 'standby', + }, + { + name: 'core:ManufacturerNameState', + type: 3, + value: 'Atlantic', + }, + { + name: 'io:ModelState', + type: 3, + value: 'AGILIA H PI-io', + }, + { + name: 'io:PowerState', + type: 1, + value: 750, + }, + { + name: 'io:TensionState', + type: 1, + value: 230, + }, + { + name: 'core:DerogatedTargetTemperatureState', + type: 2, + value: 0, + }, + { + name: 'io:NativeFunctionalLevelState', + type: 3, + value: 'Top', + }, + { + name: 'io:TemperatureProbeCalibrationOffsetState', + type: 2, + value: 0, + }, + { + name: 'io:CurrentWorkingRateState', + type: 2, + value: 0, + }, + { + name: 'io:CumulatedLoweringState', + type: 2, + value: 0, + }, + { + name: 'io:RoomDeletionThresholdState', + type: 3, + value: '-2°C', + }, + { + name: 'io:EffectiveTemperatureSetpointState', + type: 2, + value: 16, + }, + { + name: 'io:ControllerAddressState', + type: 1, + value: 6412160, + }, + { + name: 'io:ExpectedPresenceState', + type: 3, + value: '20:30', + lastUpdateTime: 1601921551000, + }, + { + name: 'io:AutoProgramState', + type: 11, + value: { + sunday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + saturday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_1', + 'CONF_1', + 'CONF_2', + 'CONF_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + tuesday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_1', + 'CONF_1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + wednesday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_NIV2', + 'CONF_1', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + thursday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + friday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_3_NIV2', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_3_NIV2', + 'CONF_2', + 'CONF_2', + 'CONF_3_NIV2', + 'CONF_NIV1', + 'CONF_3_NIV1', + 'CONF_NIV3', + 'CONF_NIV2', + 'CONF_3_NIV1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + anticipTime: 1598, + anticipNb: 20, + monday: [ + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_1', + 'CONF_1', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_NIV2', + 'CONF_1', + 'CONF_3_NIV1', + 'CONF_2', + 'CONF_1', + 'CONF_3_NIV2', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + 'CONF_3_NIV1', + ], + }, + }, + { + name: 'core:PreviousTargetTemperatureState', + type: 2, + value: 17, + }, + { + name: 'core:TimeProgramState', + type: 10, + value: [ + { + monday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + tuesday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + wednesday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + thursday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + friday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + saturday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + { + sunday: [ + { + start: '07:00', + end: '20:00', + }, + { + start: '00:00', + end: '00:00', + }, + { + start: '00:00', + end: '00:00', + }, + ], + }, + ], + }, + ], + attributes: [ + { + name: 'core:Manufacturer', + type: 3, + value: 'Atlantic Group', + }, + { + name: 'core:FirmwareRevision', + type: 3, + value: 'I741008', + }, + ], + available: true, + enabled: true, + placeOID: '2de0b602-9a42-48d3-9c9f-42bc192c8783', + place: 'Maxime', + widget: 'AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint', + type: 1, + oid: '29bbe178-d3e3-4322-85dd-cafc8148cf41', + uiClass: 'HeatingSystem', + }, + features: [ + { + name: 'Temperature', + selector: 'overkiz-0a9055f2-6748-4f7b-b6f1-e396cc13203b-temperaturesensor', + category: 'temperature-sensor', + type: 'decimal', + external_id: 'overkiz-0a9055f2-6748-4f7b-b6f1-e396cc13203b-TemperatureSensor', + read_only: true, + unit: 'celsius', + has_feedback: true, + min: 0, + max: 40, + }, + { + name: 'Occupancy', + selector: 'overkiz-357d8eb4-7bb5-45bf-a6ab-afa7460b673a-occupancysensor', + category: 'presence-sensor', + type: 'push', + external_id: 'overkiz-357d8eb4-7bb5-45bf-a6ab-afa7460b673a-OccupancySensor', + read_only: true, + has_feedback: false, + keep_history: true, + min: 0, + max: 1, + }, + ], + params: [ + { + name: 'ONLINE', + value: 'available', + }, + { + name: 'FIRMWARE', + value: 'I741008', + }, + ], + }, + ]); + }); +}); diff --git a/server/test/services/overkiz/overkiz_devices.json b/server/test/services/overkiz/overkiz_devices.json new file mode 100644 index 0000000000..cccc84fb33 --- /dev/null +++ b/server/test/services/overkiz/overkiz_devices.json @@ -0,0 +1,5000 @@ +{ + "creationTime": 1586773014000, + "lastUpdateTime": 1586773014000, + "id": "SETUP-0814-0291-7832", + "location": { + "creationTime": 1586773014000, + "lastUpdateTime": 1635610555000, + "city": "xxx", + "country": "Belgium", + "postalCode": "xxx", + "addressLine1": "xxx", + "timezone": "Europe/Brussels", + "longitude": 2.343, + "latitude": 48.857, + "twilightMode": 2, + "twilightAngle": "CIVIL", + "twilightCity": "bruxelles", + "summerSolsticeDuskMinutes": 1290, + "winterSolsticeDuskMinutes": 990, + "twilightOffsetEnabled": false, + "dawnOffset": 0, + "duskOffset": 0, + "tariffSettings": { + "tariffMode": "offPeakHours", + "tariffs": [ + { + "name": "tariff1", + "startTime": "00:00" + }, + { + "name": "tariff2", + "startTime": "06:00" + }, + { + "name": "tariff1", + "startTime": "22:00" + } + ] + }, + "countryCode": "BE" + }, + "gateways": [ + { + "gatewayId": "0814-0291-7832", + "type": 32, + "subType": 0, + "placeOID": "ebd3b36a-dd8f-4012-90c3-6ab51607e889", + "alive": true, + "timeReliable": true, + "connectivity": { + "status": "OK", + "protocolVersion": "2021.5.4" + }, + "upToDate": true, + "updateStatus": "UP_TO_DATE", + "syncInProgress": false, + "functions": "INTERNET_AUTHORIZATION,SCENARIO_DOWNLOAD,SCENARIO_AUTO_LAUNCHING,SCENARIO_TELECO_LAUNCHING,INTERNET_UPLOAD,INTERNET_UPDATE,TRIGGERS_SENSORS", + "mode": "ACTIVE" + } + ], + "devices": [ + { + "creationTime": 1586773014000, + "lastUpdateTime": 1586773014000, + "label": "Box", + "deviceURL": "internal://0814-0291-7832/pod/0", + "shortcut": false, + "controllableName": "internal:PodMiniComponent", + "definition": { + "commands": [ + { + "commandName": "getName", + "nparams": 0 + }, + { + "commandName": "update", + "nparams": 0 + }, + { + "commandName": "setCountryCode", + "nparams": 1 + }, + { + "commandName": "activateCalendar", + "nparams": 0 + }, + { + "commandName": "deactivateCalendar", + "nparams": 0 + }, + { + "commandName": "refreshPodMode", + "nparams": 0 + }, + { + "commandName": "refreshUpdateStatus", + "nparams": 0 + }, + { + "commandName": "setCalendar", + "nparams": 1 + }, + { + "commandName": "setLightingLedPodMode", + "nparams": 1 + }, + { + "commandName": "setPodLedOff", + "nparams": 0 + }, + { + "commandName": "setPodLedOn", + "nparams": 0 + } + ], + "states": [ + { + "type": "DiscreteState", + "values": ["offline", "online"], + "qualifiedName": "core:ConnectivityState" + }, + { + "type": "DataState", + "qualifiedName": "core:CountryCodeState" + }, + { + "type": "DataState", + "qualifiedName": "core:LocalIPv4AddressState" + }, + { + "type": "DataState", + "qualifiedName": "core:NameState" + }, + { + "type": "DiscreteState", + "values": ["doublePress", "longPress", "simplePress", "triplePress", "veryLongPress"], + "qualifiedName": "internal:LastActionConfigButtonState" + }, + { + "type": "ContinuousState", + "qualifiedName": "internal:LightingLedPodModeState" + } + ], + "dataProperties": [], + "widgetName": "Pod", + "uiProfiles": ["UpdatableComponent"], + "uiClass": "Pod", + "qualifiedName": "internal:PodMiniComponent", + "type": "ACTUATOR" + }, + "states": [ + { + "name": "core:NameState", + "type": 3, + "value": "Box" + }, + { + "name": "internal:LightingLedPodModeState", + "type": 2, + "value": 1 + }, + { + "name": "core:CountryCodeState", + "type": 3, + "value": "BE" + }, + { + "name": "core:LocalIPv4AddressState", + "type": 3, + "value": "192.168.1.20" + } + ], + "available": true, + "enabled": true, + "placeOID": "ebd3b36a-dd8f-4012-90c3-6ab51607e889", + "widget": "Pod", + "type": 1, + "oid": "50d30409-4949-4122-a674-aaacc0d28cc4", + "uiClass": "Pod" + }, + { + "creationTime": 1601921868000, + "lastUpdateTime": 1601921868000, + "label": "Radiateur", + "deviceURL": "io://0814-0291-7832/11410052#1", + "shortcut": false, + "controllableName": "io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent", + "definition": { + "commands": [ + { + "commandName": "advancedRefresh", + "nparams": 1 + }, + { + "commandName": "cancelHeatingLevel", + "nparams": 1 + }, + { + "commandName": "delayedStopIdentify", + "nparams": 1 + }, + { + "commandName": "getName", + "nparams": 0 + }, + { + "commandName": "identify", + "nparams": 0 + }, + { + "commandName": "noPersonInside", + "nparams": 0 + }, + { + "commandName": "off", + "nparams": 0 + }, + { + "commandName": "personInside", + "nparams": 0 + }, + { + "commandName": "refreshComfortTemperature", + "nparams": 0 + }, + { + "commandName": "refreshDateTime", + "nparams": 0 + }, + { + "commandName": "refreshDerogatedTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshEcoTemperature", + "nparams": 0 + }, + { + "commandName": "refreshHeatingLevel", + "nparams": 0 + }, + { + "commandName": "refreshIdentifier", + "nparams": 0 + }, + { + "commandName": "refreshManufacturerName", + "nparams": 0 + }, + { + "commandName": "refreshMaximumHeatingTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshMaximumTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshOperatingMode", + "nparams": 0 + }, + { + "commandName": "refreshTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshTemperature", + "nparams": 0 + }, + { + "commandName": "refreshTimeProgram", + "nparams": 0 + }, + { + "commandName": "setComfortTemperature", + "nparams": 1 + }, + { + "commandName": "setDateTime", + "nparams": 1 + }, + { + "commandName": "setDerogatedTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setEcoTemperature", + "nparams": 1 + }, + { + "commandName": "setHeatingLevel", + "nparams": 1 + }, + { + "commandName": "setHeatingLevelWithTimer", + "nparams": 2 + }, + { + "commandName": "setHolidays", + "nparams": 1 + }, + { + "commandName": "setHolidaysTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setName", + "nparams": 1 + }, + { + "commandName": "setOccupancyActivation", + "nparams": 1 + }, + { + "commandName": "setOccupancy", + "nparams": 1 + }, + { + "commandName": "setOpenWindowDetectionActivation", + "nparams": 1 + }, + { + "commandName": "setOperatingMode", + "nparams": 1 + }, + { + "commandName": "setPreviousTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setSchedulingType", + "nparams": 1 + }, + { + "commandName": "setTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setTimeProgram", + "nparams": 1 + }, + { + "commandName": "startIdentify", + "nparams": 0 + }, + { + "commandName": "stopIdentify", + "nparams": 0 + }, + { + "commandName": "wink", + "nparams": 1 + }, + { + "commandName": "pairOneWayController", + "nparams": 2 + }, + { + "commandName": "refreshAutoProgram", + "nparams": 0 + }, + { + "commandName": "refreshControllerAddress", + "nparams": 0 + }, + { + "commandName": "refreshCumulatedLowering", + "nparams": 0 + }, + { + "commandName": "refreshCurrentWorkingRate", + "nparams": 0 + }, + { + "commandName": "refreshDeletionCancelation", + "nparams": 0 + }, + { + "commandName": "refreshEffectiveTemperatureSetpoint", + "nparams": 0 + }, + { + "commandName": "refreshLocalLeadTime", + "nparams": 0 + }, + { + "commandName": "refreshModel", + "nparams": 0 + }, + { + "commandName": "refreshNativeFunctionalLevel", + "nparams": 0 + }, + { + "commandName": "refreshPeakNotice", + "nparams": 0 + }, + { + "commandName": "refreshPeakWarning", + "nparams": 0 + }, + { + "commandName": "refreshPowerAndTension", + "nparams": 0 + }, + { + "commandName": "refreshRoomDeletionThreshold", + "nparams": 0 + }, + { + "commandName": "refreshSetpointLoweringTemperatureInProgMode", + "nparams": 0 + }, + { + "commandName": "refreshSynchronisationRequest", + "nparams": 0 + }, + { + "commandName": "refreshTemperatureProbeCalibrationOffset", + "nparams": 0 + }, + { + "commandName": "setCommunicationTest", + "nparams": 1 + }, + { + "commandName": "setDeletionCancelation", + "nparams": 1 + }, + { + "commandName": "setExpectedPresence", + "nparams": 1 + }, + { + "commandName": "setHeatingLevelForTrigger", + "nparams": 1 + }, + { + "commandName": "setNativeLevelsList", + "nparams": 1 + }, + { + "commandName": "setPeakNotice", + "nparams": 1 + }, + { + "commandName": "setPeakWarning", + "nparams": 1 + }, + { + "commandName": "setRoomDeletionThreshold", + "nparams": 1 + }, + { + "commandName": "setSetpointLoweringTemperatureInProgMode", + "nparams": 1 + }, + { + "commandName": "setTemperatureProbeCalibrationOffset", + "nparams": 1 + }, + { + "commandName": "setTwinningExit", + "nparams": 1 + }, + { + "commandName": "unpairAllOneWayControllers", + "nparams": 0 + }, + { + "commandName": "unpairOneWayController", + "nparams": 2 + } + ], + "states": [ + { + "type": "ContinuousState", + "qualifiedName": "core:ComfortRoomTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:DateTimeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:DerogatedTargetTemperatureState" + }, + { + "type": "DiscreteState", + "values": ["good", "low", "normal", "verylow"], + "qualifiedName": "core:DiscreteRSSILevelState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:EcoRoomTemperatureState" + }, + { + "type": "DiscreteState", + "values": ["off", "on"], + "qualifiedName": "core:HolidaysModeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:HolidaysTargetTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:IdentifierState" + }, + { + "type": "DataState", + "qualifiedName": "core:ManufacturerNameState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:MaximumHeatingTargetTemperatureState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:MaximumTargetTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:NameState" + }, + { + "type": "DiscreteState", + "values": ["active", "inactive"], + "qualifiedName": "core:OccupancyActivationState" + }, + { + "type": "DiscreteState", + "values": ["off", "on"], + "qualifiedName": "core:OnOffState" + }, + { + "type": "DiscreteState", + "values": ["active", "inactive"], + "qualifiedName": "core:OpenWindowDetectionActivationState" + }, + { + "type": "DiscreteState", + "values": [ + "antifreeze", + "auto", + "away", + "eco", + "frostprotection", + "manual", + "max", + "normal", + "off", + "on", + "prog", + "program", + "boost" + ], + "qualifiedName": "core:OperatingModeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:PreviousTargetTemperatureState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:PriorityLockTimerState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:RSSILevelState" + }, + { + "type": "DiscreteState", + "values": ["increase", "none", "standby"], + "qualifiedName": "core:RegulationModeState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:TargetTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:TimeProgramState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:VersionState" + }, + { + "type": "DataState", + "qualifiedName": "io:AutoProgramState" + }, + { + "type": "DataState", + "qualifiedName": "io:ControllerAddressState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:CumulatedLoweringState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:CurrentWorkingRateState" + }, + { + "type": "DiscreteState", + "values": ["deletion cancelation", "no deletion cancelation"], + "qualifiedName": "io:DeletionCancelationState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:EffectiveTemperatureSetpointState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:ExpectedPresenceState" + }, + { + "type": "DiscreteState", + "values": ["external", "internal"], + "qualifiedName": "io:InternalExternalSchedulingTypeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:LocalLeadTimeState" + }, + { + "type": "DiscreteState", + "values": ["boost", "comfort", "comfort-1", "comfort-2", "eco", "frostprotection", "off", "secured"], + "qualifiedName": "io:MaximumHeatingLevelState" + }, + { + "type": "DataState", + "qualifiedName": "io:ModelState" + }, + { + "type": "DiscreteState", + "values": ["base", "medium", "top"], + "qualifiedName": "io:NativeFunctionalLevelState" + }, + { + "type": "DiscreteState", + "values": ["long peak", "no peak", "short peak"], + "qualifiedName": "io:PeakNoticeState" + }, + { + "type": "DiscreteState", + "values": ["long peak warning", "no warning", "short peak warning"], + "qualifiedName": "io:PeakWarningState" + }, + { + "type": "DataState", + "qualifiedName": "io:PowerState" + }, + { + "type": "DiscreteState", + "values": [ + "comfortLevel1", + "comfortLevel2", + "comfortLevel3", + "comfortLevel4", + "environmentProtection", + "humanProtection", + "userLevel1", + "userLevel2" + ], + "qualifiedName": "io:PriorityLockLevelState" + }, + { + "type": "DiscreteState", + "values": [ + "LSC", + "SAAC", + "SFC", + "UPS", + "externalGateway", + "localUser", + "myself", + "rain", + "security", + "temperature", + "timer", + "user", + "wind" + ], + "qualifiedName": "io:PriorityLockOriginatorState" + }, + { + "type": "DataState", + "qualifiedName": "io:RoomDeletionThresholdState" + }, + { + "type": "DiscreteState", + "values": ["kept", "lost"], + "qualifiedName": "io:RunningState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:SetpointLoweringTemperatureInProgModeState" + }, + { + "type": "DiscreteState", + "values": ["boost", "comfort", "comfort-1", "comfort-2", "eco", "frostprotection", "off", "secured"], + "qualifiedName": "io:TargetHeatingLevelState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:TemperatureProbeCalibrationOffsetState" + }, + { + "type": "DataState", + "qualifiedName": "io:TensionState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:TimerForTransitoryStateState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:UptimeState" + } + ], + "dataProperties": [ + { + "value": "500", + "qualifiedName": "core:identifyInterval" + } + ], + "widgetName": "AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint", + "uiProfiles": ["StatefulOperatingModeHeating", "OperatingModeHeating", "StatefulThermostat", "Thermostat"], + "uiClass": "HeatingSystem", + "uiClassifiers": ["emitter"], + "qualifiedName": "io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent", + "type": "ACTUATOR" + }, + "states": [ + { + "name": "core:NameState", + "type": 3, + "value": "Radiateur" + }, + { + "name": "core:VersionState", + "type": 3, + "value": "49373431303038202020" + }, + { + "name": "core:PriorityLockTimerState", + "type": 1, + "value": 0 + }, + { + "name": "core:OnOffState", + "type": 3, + "value": "on" + }, + { + "name": "io:TargetHeatingLevelState", + "type": 3, + "value": "comfort" + }, + { + "name": "core:StatusState", + "type": 3, + "value": "available" + }, + { + "name": "core:DiscreteRSSILevelState", + "type": 3, + "value": "low" + }, + { + "name": "core:RSSILevelState", + "type": 2, + "value": 30 + }, + { + "name": "core:IdentifierState", + "type": 3, + "value": "00000000" + }, + { + "name": "io:MaximumHeatingLevelState", + "type": 3, + "value": "unknown" + }, + { + "name": "io:TimerForTransitoryStateState", + "type": 1, + "value": 0 + }, + { + "name": "core:ComfortRoomTemperatureState", + "type": 1, + "value": 24 + }, + { + "name": "core:EcoRoomTemperatureState", + "type": 1, + "value": 8 + }, + { + "name": "core:OperatingModeState", + "type": 3, + "value": "internal" + }, + { + "name": "core:OccupancyActivationState", + "type": 3, + "value": "inactive" + }, + { + "name": "core:MaximumHeatingTargetTemperatureState", + "type": 2, + "value": 28 + }, + { + "name": "core:MaximumTargetTemperatureState", + "type": 2, + "value": 28 + }, + { + "name": "core:TargetTemperatureState", + "type": 2, + "value": 24 + }, + { + "name": "io:SetpointLoweringTemperatureInProgModeState", + "type": 2, + "value": 8 + }, + { + "name": "core:OpenWindowDetectionActivationState", + "type": 3, + "value": "inactive" + }, + { + "name": "io:InternalExternalSchedulingTypeState", + "type": 3, + "value": "internal" + }, + { + "name": "core:DateTimeState", + "type": 11, + "value": { + "month": 1, + "hour": 11, + "year": 2022, + "weekday": 3, + "day": 6, + "minute": 44, + "second": 48 + } + }, + { + "name": "io:LocalLeadTimeState", + "type": 1, + "value": 4394 + }, + { + "name": "core:RegulationModeState", + "type": 3, + "value": "standby" + }, + { + "name": "core:ManufacturerNameState", + "type": 3, + "value": "Atlantic" + }, + { + "name": "io:ModelState", + "type": 3, + "value": "AGILIA H PI-io" + }, + { + "name": "io:PowerState", + "type": 1, + "value": 750 + }, + { + "name": "io:TensionState", + "type": 1, + "value": 230 + }, + { + "name": "core:DerogatedTargetTemperatureState", + "type": 2, + "value": 0 + }, + { + "name": "io:NativeFunctionalLevelState", + "type": 3, + "value": "Top" + }, + { + "name": "io:TemperatureProbeCalibrationOffsetState", + "type": 2, + "value": 0 + }, + { + "name": "io:CurrentWorkingRateState", + "type": 2, + "value": 0 + }, + { + "name": "io:CumulatedLoweringState", + "type": 2, + "value": 0 + }, + { + "name": "io:RoomDeletionThresholdState", + "type": 3, + "value": "-2°C" + }, + { + "name": "io:EffectiveTemperatureSetpointState", + "type": 2, + "value": 16 + }, + { + "name": "io:ControllerAddressState", + "type": 1, + "value": 11410051 + }, + { + "name": "io:ExpectedPresenceState", + "type": 3, + "value": "17:30", + "lastUpdateTime": 1607184038000 + }, + { + "name": "io:AutoProgramState", + "type": 11, + "value": { + "sunday": [ + "CONF_3_NIV1", + "CONF_2", + "CONF_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_NIV2", + "CONF_NIV2", + "CONF_NIV1", + "CONF_NIV2", + "CONF_1", + "CONF_NIV1", + "CONF_NIV3", + "CONF_NIV3", + "CONF_NIV2", + "CONF_NIV2", + "CONF_2", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_NIV3", + "CONF_NIV3", + "CONF_NIV3", + "CONF_1", + "CONF_1", + "CONF_1", + "CONF_NIV2", + "CONF_1", + "CONF_NIV3", + "CONF_1", + "CONF_NIV2", + "CONF_3_NIV2", + "CONF_2", + "CONF_NIV2", + "CONF_NIV1", + "CONF_3_NIV2" + ], + "saturday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_NIV1", + "CONF_2", + "CONF_2", + "CONF_3_NIV1", + "CONF_NIV2", + "CONF_NIV2", + "CONF_NIV1", + "CONF_3_NIV2", + "CONF_1", + "CONF_NIV2", + "CONF_NIV1", + "CONF_3_NIV2", + "CONF_NIV1", + "CONF_NIV2", + "CONF_NIV2", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_NIV1", + "CONF_3_NIV2", + "CONF_2", + "CONF_NIV2", + "CONF_NIV1", + "CONF_3_NIV1", + "CONF_NIV2", + "CONF_NIV3", + "CONF_NIV2", + "CONF_NIV1", + "CONF_1", + "CONF_2" + ], + "tuesday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_NIV3", + "CONF_2", + "CONF_NIV1", + "CONF_3_NIV2", + "CONF_NIV1", + "CONF_2", + "CONF_2", + "CONF_3_NIV2", + "CONF_3_NIV2", + "CONF_3_NIV2", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_1", + "CONF_3_NIV1", + "CONF_NIV2", + "CONF_1", + "CONF_2", + "CONF_3_NIV2", + "CONF_NIV3", + "CONF_NIV3", + "CONF_NIV3", + "CONF_NIV2", + "CONF_NIV3", + "CONF_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2" + ], + "wednesday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_NIV1", + "CONF_NIV3", + "CONF_1", + "CONF_NIV1", + "CONF_NIV3", + "CONF_2", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_NIV1", + "CONF_NIV3", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_NIV2", + "CONF_1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_NIV2", + "CONF_NIV1", + "CONF_NIV3", + "CONF_3_NIV1", + "CONF_NIV3", + "CONF_NIV2", + "CONF_NIV2", + "CONF_NIV1", + "CONF_NIV2", + "CONF_2", + "CONF_NIV3", + "CONF_2", + "CONF_3_NIV1", + "CONF_NIV1", + "CONF_1", + "CONF_3_NIV2" + ], + "thursday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_1", + "CONF_1", + "CONF_NIV2", + "CONF_NIV3", + "CONF_NIV3", + "CONF_NIV3", + "CONF_NIV2", + "CONF_NIV1", + "CONF_1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV2", + "CONF_2", + "CONF_2", + "CONF_1", + "CONF_1", + "CONF_NIV2", + "CONF_NIV2", + "CONF_3_NIV1", + "CONF_NIV1", + "CONF_NIV3", + "CONF_3_NIV2", + "CONF_NIV3", + "CONF_NIV3", + "CONF_NIV1", + "CONF_NIV2", + "CONF_3_NIV1", + "CONF_NIV1", + "CONF_2", + "CONF_2" + ], + "friday": [ + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_1", + "CONF_3_NIV2", + "CONF_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_NIV2", + "CONF_NIV2", + "CONF_NIV3", + "CONF_2", + "CONF_2", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_NIV1", + "CONF_2", + "CONF_2", + "CONF_NIV3", + "CONF_NIV2", + "CONF_NIV3", + "CONF_NIV3", + "CONF_NIV3", + "CONF_NIV1", + "CONF_NIV1", + "CONF_1", + "CONF_3_NIV1", + "CONF_1", + "CONF_1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_1", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1" + ], + "anticipTime": 4394, + "anticipNb": 20, + "monday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_NIV1", + "CONF_1", + "CONF_NIV3", + "CONF_1", + "CONF_2", + "CONF_3_NIV2", + "CONF_NIV2", + "CONF_2", + "CONF_NIV1", + "CONF_2", + "CONF_3_NIV2", + "CONF_NIV3", + "CONF_1", + "CONF_NIV2", + "CONF_NIV3", + "CONF_2", + "CONF_1", + "CONF_3_NIV1", + "CONF_1", + "CONF_NIV3", + "CONF_NIV2", + "CONF_NIV1", + "CONF_1", + "CONF_2", + "CONF_3_NIV2", + "CONF_NIV3", + "CONF_NIV3", + "CONF_1", + "CONF_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_1", + "CONF_NIV1", + "CONF_3_NIV1" + ] + } + }, + { + "name": "core:TimeProgramState", + "type": 10, + "value": [ + { + "monday": [ + { + "start": "05:30", + "end": "08:30" + }, + { + "start": "18:30", + "end": "21:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "tuesday": [ + { + "start": "05:30", + "end": "08:30" + }, + { + "start": "18:30", + "end": "21:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "wednesday": [ + { + "start": "06:30", + "end": "08:30" + }, + { + "start": "18:30", + "end": "21:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "thursday": [ + { + "start": "05:30", + "end": "08:30" + }, + { + "start": "18:00", + "end": "21:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "friday": [ + { + "start": "05:30", + "end": "08:30" + }, + { + "start": "18:30", + "end": "21:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "saturday": [ + { + "start": "05:30", + "end": "08:30" + }, + { + "start": "17:00", + "end": "21:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "sunday": [ + { + "start": "05:30", + "end": "08:30" + }, + { + "start": "18:30", + "end": "21:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + } + ] + } + ], + "attributes": [ + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + } + ], + "available": true, + "enabled": true, + "placeOID": "9abb0634-9b62-476f-8a60-0a63463e011b", + "widget": "AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint", + "type": 1, + "oid": "fbb6f179-92b4-479a-9c53-41607e3c7a15", + "uiClass": "HeatingSystem" + }, + { + "creationTime": 1601921868000, + "lastUpdateTime": 1601921868000, + "label": "IO (11410052#2)", + "deviceURL": "io://0814-0291-7832/11410052#2", + "shortcut": false, + "controllableName": "io:TemperatureInCelciusIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:TemperatureState" + } + ], + "dataProperties": [], + "widgetName": "TemperatureSensor", + "uiProfiles": ["Temperature"], + "uiClass": "TemperatureSensor", + "qualifiedName": "io:TemperatureInCelciusIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "available" + }, + { + "name": "core:TemperatureState", + "type": 2, + "value": 23.4 + } + ], + "attributes": [ + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:MeasuredValueType", + "type": 3, + "value": "core:TemperatureInCelcius" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + } + ], + "available": true, + "enabled": true, + "placeOID": "9abb0634-9b62-476f-8a60-0a63463e011b", + "widget": "TemperatureSensor", + "type": 2, + "oid": "45eca6ef-5a88-4858-a84c-f9614258f966", + "uiClass": "TemperatureSensor" + }, + { + "creationTime": 1601921868000, + "lastUpdateTime": 1601921868000, + "label": "IO (11410052#3)", + "deviceURL": "io://0814-0291-7832/11410052#3", + "shortcut": false, + "controllableName": "io:ContactIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "type": "DiscreteState", + "values": ["closed", "open"], + "qualifiedName": "core:ContactState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + } + ], + "dataProperties": [], + "widgetName": "ContactSensor", + "uiProfiles": ["DoorContactSensor", "ContactDetector"], + "uiClass": "ContactSensor", + "qualifiedName": "io:ContactIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "available" + }, + { + "name": "core:ContactState", + "type": 3, + "value": "closed" + } + ], + "attributes": [ + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + } + ], + "available": true, + "enabled": true, + "placeOID": "9abb0634-9b62-476f-8a60-0a63463e011b", + "widget": "ContactSensor", + "type": 2, + "oid": "a158c7c4-65d3-4e31-b67a-c91e358a7c17", + "uiClass": "ContactSensor" + }, + { + "creationTime": 1601921868000, + "lastUpdateTime": 1601921868000, + "label": "IO (11410052#4)", + "deviceURL": "io://0814-0291-7832/11410052#4", + "shortcut": false, + "controllableName": "io:OccupancyIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "eventBased": true, + "type": "DiscreteState", + "values": ["noPersonInside", "personInside"], + "qualifiedName": "core:OccupancyState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + } + ], + "dataProperties": [], + "widgetName": "OccupancySensor", + "uiProfiles": ["OccupancyDetector"], + "uiClass": "OccupancySensor", + "qualifiedName": "io:OccupancyIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "available" + }, + { + "name": "core:OccupancyState", + "type": 3, + "value": "noPersonInside" + } + ], + "attributes": [ + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + } + ], + "available": true, + "enabled": true, + "placeOID": "9abb0634-9b62-476f-8a60-0a63463e011b", + "widget": "OccupancySensor", + "type": 2, + "oid": "2263edf8-95b5-41e8-8c59-a44c89aabe6f", + "uiClass": "OccupancySensor" + }, + { + "creationTime": 1601921868000, + "lastUpdateTime": 1601921868000, + "label": "IO (11410052#5)", + "deviceURL": "io://0814-0291-7832/11410052#5", + "shortcut": false, + "controllableName": "io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff0State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff1State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff2State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff3State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff4State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff5State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff6State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff7State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff8State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff9State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ElectricEnergyConsumptionState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + } + ], + "dataProperties": [], + "widgetName": "CumulativeElectricPowerConsumptionSensor", + "uiProfiles": ["ElectricEnergyConsumption"], + "uiClass": "ElectricitySensor", + "qualifiedName": "io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "available" + }, + { + "name": "core:ElectricEnergyConsumptionState", + "type": 1, + "value": 525000 + }, + { + "name": "core:ConsumptionTariff1State", + "type": 1, + "value": 62000 + }, + { + "name": "core:ConsumptionTariff2State", + "type": 1, + "value": 291000 + } + ], + "attributes": [ + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + }, + { + "name": "core:MeasuredValueType", + "type": 3, + "value": "core:ElectricalEnergyInWh" + } + ], + "available": true, + "enabled": true, + "placeOID": "9abb0634-9b62-476f-8a60-0a63463e011b", + "widget": "CumulativeElectricPowerConsumptionSensor", + "type": 2, + "oid": "3d8317f1-5cfa-475d-9766-582909112fe0", + "uiClass": "ElectricitySensor" + }, + { + "creationTime": 1601391514000, + "lastUpdateTime": 1601391514000, + "label": "IO (15909334)", + "deviceURL": "io://0814-0291-7832/15909334", + "shortcut": false, + "controllableName": "io:StackComponent", + "definition": { + "commands": [ + { + "commandName": "advancedSomfyDiscover", + "nparams": 1 + }, + { + "commandName": "discover1WayController", + "nparams": 2 + }, + { + "commandName": "discoverActuators", + "nparams": 1 + }, + { + "commandName": "discoverSensors", + "nparams": 1 + }, + { + "commandName": "discoverSomfyUnsetActuators", + "nparams": 0 + }, + { + "commandName": "joinNetwork", + "nparams": 0 + }, + { + "commandName": "resetNetworkSecurity", + "nparams": 0 + }, + { + "commandName": "shareNetwork", + "nparams": 0 + } + ], + "states": [], + "dataProperties": [], + "widgetName": "IOStack", + "uiProfiles": ["Specific"], + "uiClass": "ProtocolGateway", + "qualifiedName": "io:StackComponent", + "type": "PROTOCOL_GATEWAY" + }, + "available": true, + "enabled": true, + "placeOID": "ebd3b36a-dd8f-4012-90c3-6ab51607e889", + "widget": "IOStack", + "type": 5, + "oid": "c40edcea-4d8c-4223-af1c-696abd4e94ff", + "uiClass": "ProtocolGateway" + }, + { + "creationTime": 1588332894000, + "lastUpdateTime": 1588332894000, + "label": "Radiateur", + "deviceURL": "io://0814-0291-7832/5276217#1", + "shortcut": false, + "controllableName": "io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent", + "definition": { + "commands": [ + { + "commandName": "advancedRefresh", + "nparams": 1 + }, + { + "commandName": "cancelHeatingLevel", + "nparams": 1 + }, + { + "commandName": "delayedStopIdentify", + "nparams": 1 + }, + { + "commandName": "getName", + "nparams": 0 + }, + { + "commandName": "identify", + "nparams": 0 + }, + { + "commandName": "noPersonInside", + "nparams": 0 + }, + { + "commandName": "off", + "nparams": 0 + }, + { + "commandName": "personInside", + "nparams": 0 + }, + { + "commandName": "refreshComfortTemperature", + "nparams": 0 + }, + { + "commandName": "refreshDateTime", + "nparams": 0 + }, + { + "commandName": "refreshDerogatedTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshEcoTemperature", + "nparams": 0 + }, + { + "commandName": "refreshHeatingLevel", + "nparams": 0 + }, + { + "commandName": "refreshIdentifier", + "nparams": 0 + }, + { + "commandName": "refreshManufacturerName", + "nparams": 0 + }, + { + "commandName": "refreshMaximumHeatingTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshMaximumTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshOperatingMode", + "nparams": 0 + }, + { + "commandName": "refreshTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshTemperature", + "nparams": 0 + }, + { + "commandName": "refreshTimeProgram", + "nparams": 0 + }, + { + "commandName": "setComfortTemperature", + "nparams": 1 + }, + { + "commandName": "setDateTime", + "nparams": 1 + }, + { + "commandName": "setDerogatedTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setEcoTemperature", + "nparams": 1 + }, + { + "commandName": "setHeatingLevel", + "nparams": 1 + }, + { + "commandName": "setHeatingLevelWithTimer", + "nparams": 2 + }, + { + "commandName": "setHolidays", + "nparams": 1 + }, + { + "commandName": "setHolidaysTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setName", + "nparams": 1 + }, + { + "commandName": "setOccupancyActivation", + "nparams": 1 + }, + { + "commandName": "setOccupancy", + "nparams": 1 + }, + { + "commandName": "setOpenWindowDetectionActivation", + "nparams": 1 + }, + { + "commandName": "setOperatingMode", + "nparams": 1 + }, + { + "commandName": "setPreviousTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setSchedulingType", + "nparams": 1 + }, + { + "commandName": "setTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setTimeProgram", + "nparams": 1 + }, + { + "commandName": "startIdentify", + "nparams": 0 + }, + { + "commandName": "stopIdentify", + "nparams": 0 + }, + { + "commandName": "wink", + "nparams": 1 + }, + { + "commandName": "pairOneWayController", + "nparams": 2 + }, + { + "commandName": "refreshAutoProgram", + "nparams": 0 + }, + { + "commandName": "refreshControllerAddress", + "nparams": 0 + }, + { + "commandName": "refreshCumulatedLowering", + "nparams": 0 + }, + { + "commandName": "refreshCurrentWorkingRate", + "nparams": 0 + }, + { + "commandName": "refreshDeletionCancelation", + "nparams": 0 + }, + { + "commandName": "refreshEffectiveTemperatureSetpoint", + "nparams": 0 + }, + { + "commandName": "refreshLocalLeadTime", + "nparams": 0 + }, + { + "commandName": "refreshModel", + "nparams": 0 + }, + { + "commandName": "refreshNativeFunctionalLevel", + "nparams": 0 + }, + { + "commandName": "refreshPeakNotice", + "nparams": 0 + }, + { + "commandName": "refreshPeakWarning", + "nparams": 0 + }, + { + "commandName": "refreshPowerAndTension", + "nparams": 0 + }, + { + "commandName": "refreshRoomDeletionThreshold", + "nparams": 0 + }, + { + "commandName": "refreshSetpointLoweringTemperatureInProgMode", + "nparams": 0 + }, + { + "commandName": "refreshSynchronisationRequest", + "nparams": 0 + }, + { + "commandName": "refreshTemperatureProbeCalibrationOffset", + "nparams": 0 + }, + { + "commandName": "setCommunicationTest", + "nparams": 1 + }, + { + "commandName": "setDeletionCancelation", + "nparams": 1 + }, + { + "commandName": "setExpectedPresence", + "nparams": 1 + }, + { + "commandName": "setHeatingLevelForTrigger", + "nparams": 1 + }, + { + "commandName": "setNativeLevelsList", + "nparams": 1 + }, + { + "commandName": "setPeakNotice", + "nparams": 1 + }, + { + "commandName": "setPeakWarning", + "nparams": 1 + }, + { + "commandName": "setRoomDeletionThreshold", + "nparams": 1 + }, + { + "commandName": "setSetpointLoweringTemperatureInProgMode", + "nparams": 1 + }, + { + "commandName": "setTemperatureProbeCalibrationOffset", + "nparams": 1 + }, + { + "commandName": "setTwinningExit", + "nparams": 1 + }, + { + "commandName": "unpairAllOneWayControllers", + "nparams": 0 + }, + { + "commandName": "unpairOneWayController", + "nparams": 2 + } + ], + "states": [ + { + "type": "ContinuousState", + "qualifiedName": "core:ComfortRoomTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:DateTimeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:DerogatedTargetTemperatureState" + }, + { + "type": "DiscreteState", + "values": ["good", "low", "normal", "verylow"], + "qualifiedName": "core:DiscreteRSSILevelState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:EcoRoomTemperatureState" + }, + { + "type": "DiscreteState", + "values": ["off", "on"], + "qualifiedName": "core:HolidaysModeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:HolidaysTargetTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:IdentifierState" + }, + { + "type": "DataState", + "qualifiedName": "core:ManufacturerNameState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:MaximumHeatingTargetTemperatureState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:MaximumTargetTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:NameState" + }, + { + "type": "DiscreteState", + "values": ["active", "inactive"], + "qualifiedName": "core:OccupancyActivationState" + }, + { + "type": "DiscreteState", + "values": ["off", "on"], + "qualifiedName": "core:OnOffState" + }, + { + "type": "DiscreteState", + "values": ["active", "inactive"], + "qualifiedName": "core:OpenWindowDetectionActivationState" + }, + { + "type": "DiscreteState", + "values": [ + "antifreeze", + "auto", + "away", + "eco", + "frostprotection", + "manual", + "max", + "normal", + "off", + "on", + "prog", + "program", + "boost" + ], + "qualifiedName": "core:OperatingModeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:PreviousTargetTemperatureState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:PriorityLockTimerState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:RSSILevelState" + }, + { + "type": "DiscreteState", + "values": ["increase", "none", "standby"], + "qualifiedName": "core:RegulationModeState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:TargetTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:TimeProgramState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:VersionState" + }, + { + "type": "DataState", + "qualifiedName": "io:AutoProgramState" + }, + { + "type": "DataState", + "qualifiedName": "io:ControllerAddressState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:CumulatedLoweringState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:CurrentWorkingRateState" + }, + { + "type": "DiscreteState", + "values": ["deletion cancelation", "no deletion cancelation"], + "qualifiedName": "io:DeletionCancelationState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:EffectiveTemperatureSetpointState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:ExpectedPresenceState" + }, + { + "type": "DiscreteState", + "values": ["external", "internal"], + "qualifiedName": "io:InternalExternalSchedulingTypeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:LocalLeadTimeState" + }, + { + "type": "DiscreteState", + "values": ["boost", "comfort", "comfort-1", "comfort-2", "eco", "frostprotection", "off", "secured"], + "qualifiedName": "io:MaximumHeatingLevelState" + }, + { + "type": "DataState", + "qualifiedName": "io:ModelState" + }, + { + "type": "DiscreteState", + "values": ["base", "medium", "top"], + "qualifiedName": "io:NativeFunctionalLevelState" + }, + { + "type": "DiscreteState", + "values": ["long peak", "no peak", "short peak"], + "qualifiedName": "io:PeakNoticeState" + }, + { + "type": "DiscreteState", + "values": ["long peak warning", "no warning", "short peak warning"], + "qualifiedName": "io:PeakWarningState" + }, + { + "type": "DataState", + "qualifiedName": "io:PowerState" + }, + { + "type": "DiscreteState", + "values": [ + "comfortLevel1", + "comfortLevel2", + "comfortLevel3", + "comfortLevel4", + "environmentProtection", + "humanProtection", + "userLevel1", + "userLevel2" + ], + "qualifiedName": "io:PriorityLockLevelState" + }, + { + "type": "DiscreteState", + "values": [ + "LSC", + "SAAC", + "SFC", + "UPS", + "externalGateway", + "localUser", + "myself", + "rain", + "security", + "temperature", + "timer", + "user", + "wind" + ], + "qualifiedName": "io:PriorityLockOriginatorState" + }, + { + "type": "DataState", + "qualifiedName": "io:RoomDeletionThresholdState" + }, + { + "type": "DiscreteState", + "values": ["kept", "lost"], + "qualifiedName": "io:RunningState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:SetpointLoweringTemperatureInProgModeState" + }, + { + "type": "DiscreteState", + "values": ["boost", "comfort", "comfort-1", "comfort-2", "eco", "frostprotection", "off", "secured"], + "qualifiedName": "io:TargetHeatingLevelState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:TemperatureProbeCalibrationOffsetState" + }, + { + "type": "DataState", + "qualifiedName": "io:TensionState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:TimerForTransitoryStateState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:UptimeState" + } + ], + "dataProperties": [ + { + "value": "500", + "qualifiedName": "core:identifyInterval" + } + ], + "widgetName": "AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint", + "uiProfiles": ["StatefulOperatingModeHeating", "OperatingModeHeating", "StatefulThermostat", "Thermostat"], + "uiClass": "HeatingSystem", + "uiClassifiers": ["emitter"], + "qualifiedName": "io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent", + "type": "ACTUATOR" + }, + "states": [ + { + "name": "core:NameState", + "type": 3, + "value": "Radiateur" + }, + { + "name": "core:VersionState", + "type": 3, + "value": "49373431303038202020" + }, + { + "name": "core:PriorityLockTimerState", + "type": 1, + "value": 0 + }, + { + "name": "core:OnOffState", + "type": 3, + "value": "on" + }, + { + "name": "io:TargetHeatingLevelState", + "type": 3, + "value": "eco" + }, + { + "name": "core:StatusState", + "type": 3, + "value": "available" + }, + { + "name": "core:DiscreteRSSILevelState", + "type": 3, + "value": "normal" + }, + { + "name": "core:RSSILevelState", + "type": 2, + "value": 60 + }, + { + "name": "core:IdentifierState", + "type": 3, + "value": "00000000" + }, + { + "name": "io:MaximumHeatingLevelState", + "type": 3, + "value": "unknown" + }, + { + "name": "io:TimerForTransitoryStateState", + "type": 1, + "value": 0 + }, + { + "name": "core:ComfortRoomTemperatureState", + "type": 1, + "value": 18 + }, + { + "name": "core:EcoRoomTemperatureState", + "type": 1, + "value": 8 + }, + { + "name": "core:OperatingModeState", + "type": 3, + "value": "internal" + }, + { + "name": "core:OccupancyActivationState", + "type": 3, + "value": "active" + }, + { + "name": "core:MaximumHeatingTargetTemperatureState", + "type": 2, + "value": 28 + }, + { + "name": "core:MaximumTargetTemperatureState", + "type": 2, + "value": 28 + }, + { + "name": "core:TargetTemperatureState", + "type": 2, + "value": 18 + }, + { + "name": "io:SetpointLoweringTemperatureInProgModeState", + "type": 2, + "value": 8 + }, + { + "name": "core:OpenWindowDetectionActivationState", + "type": 3, + "value": "active" + }, + { + "name": "io:InternalExternalSchedulingTypeState", + "type": 3, + "value": "internal" + }, + { + "name": "core:DateTimeState", + "type": 11, + "value": { + "month": 1, + "hour": 11, + "year": 2022, + "weekday": 3, + "day": 6, + "minute": 44, + "second": 9 + } + }, + { + "name": "io:LocalLeadTimeState", + "type": 1, + "value": 1625 + }, + { + "name": "core:RegulationModeState", + "type": 3, + "value": "none" + }, + { + "name": "core:ManufacturerNameState", + "type": 3, + "value": "Atlantic" + }, + { + "name": "io:ModelState", + "type": 3, + "value": "AGILIA H PI-io" + }, + { + "name": "io:PowerState", + "type": 1, + "value": 750 + }, + { + "name": "io:TensionState", + "type": 1, + "value": 230 + }, + { + "name": "core:DerogatedTargetTemperatureState", + "type": 2, + "value": 0 + }, + { + "name": "io:NativeFunctionalLevelState", + "type": 3, + "value": "Top" + }, + { + "name": "io:TemperatureProbeCalibrationOffsetState", + "type": 2, + "value": 0 + }, + { + "name": "io:CurrentWorkingRateState", + "type": 2, + "value": 0 + }, + { + "name": "io:CumulatedLoweringState", + "type": 2, + "value": 92 + }, + { + "name": "io:RoomDeletionThresholdState", + "type": 3, + "value": "-2°C" + }, + { + "name": "io:EffectiveTemperatureSetpointState", + "type": 2, + "value": 10 + }, + { + "name": "io:ControllerAddressState", + "type": 1, + "value": 5276216 + }, + { + "name": "io:ExpectedPresenceState", + "type": 3, + "value": "19:30", + "lastUpdateTime": 1607019810000 + }, + { + "name": "io:AutoProgramState", + "type": 11, + "value": { + "sunday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_1", + "CONF_3_NIV2", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_NIV1", + "CONF_2", + "CONF_3_NIV2" + ], + "saturday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1" + ], + "tuesday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_1", + "CONF_3_NIV1", + "CONF_3_NIV2" + ], + "wednesday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_1" + ], + "thursday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1" + ], + "friday": [ + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV2", + "CONF_2", + "CONF_NIV3", + "CONF_NIV3", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1" + ], + "anticipTime": 1625, + "anticipNb": 20, + "monday": [ + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_2", + "CONF_3_NIV1" + ] + } + }, + { + "name": "core:PreviousTargetTemperatureState", + "type": 2, + "value": 18 + }, + { + "name": "core:TimeProgramState", + "type": 10, + "value": [ + { + "monday": [ + { + "start": "07:00", + "end": "08:00" + }, + { + "start": "18:30", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "tuesday": [ + { + "start": "07:00", + "end": "08:00" + }, + { + "start": "18:30", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "wednesday": [ + { + "start": "07:00", + "end": "08:00" + }, + { + "start": "18:30", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "thursday": [ + { + "start": "07:00", + "end": "08:00" + }, + { + "start": "18:30", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "friday": [ + { + "start": "07:00", + "end": "08:00" + }, + { + "start": "18:30", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "saturday": [ + { + "start": "07:00", + "end": "08:00" + }, + { + "start": "18:30", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "sunday": [ + { + "start": "07:00", + "end": "08:00" + }, + { + "start": "18:30", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + } + ] + } + ], + "attributes": [ + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + } + ], + "available": true, + "enabled": true, + "placeOID": "dab51ec0-5b0c-4694-8389-7498f02d6ee6", + "widget": "AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint", + "type": 1, + "oid": "f2ca7610-248c-46a8-bf34-41edea559df5", + "uiClass": "HeatingSystem" + }, + { + "creationTime": 1588332894000, + "lastUpdateTime": 1588332894000, + "label": "IO (5276217#2)", + "deviceURL": "io://0814-0291-7832/5276217#2", + "shortcut": false, + "controllableName": "io:TemperatureInCelciusIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:TemperatureState" + } + ], + "dataProperties": [], + "widgetName": "TemperatureSensor", + "uiProfiles": ["Temperature"], + "uiClass": "TemperatureSensor", + "qualifiedName": "io:TemperatureInCelciusIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "available" + }, + { + "name": "core:TemperatureState", + "type": 2, + "value": 16.13 + } + ], + "attributes": [ + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:MeasuredValueType", + "type": 3, + "value": "core:TemperatureInCelcius" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + } + ], + "available": true, + "enabled": true, + "placeOID": "dab51ec0-5b0c-4694-8389-7498f02d6ee6", + "widget": "TemperatureSensor", + "type": 2, + "oid": "b8ea4ea5-9eb2-4d79-989b-1c73eeb5e458", + "uiClass": "TemperatureSensor" + }, + { + "creationTime": 1588332894000, + "lastUpdateTime": 1588332894000, + "label": "IO (5276217#3)", + "deviceURL": "io://0814-0291-7832/5276217#3", + "shortcut": false, + "controllableName": "io:ContactIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "type": "DiscreteState", + "values": ["closed", "open"], + "qualifiedName": "core:ContactState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + } + ], + "dataProperties": [], + "widgetName": "ContactSensor", + "uiProfiles": ["DoorContactSensor", "ContactDetector"], + "uiClass": "ContactSensor", + "qualifiedName": "io:ContactIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "available" + }, + { + "name": "core:ContactState", + "type": 3, + "value": "closed" + } + ], + "attributes": [ + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + } + ], + "available": true, + "enabled": true, + "placeOID": "dab51ec0-5b0c-4694-8389-7498f02d6ee6", + "widget": "ContactSensor", + "type": 2, + "oid": "3105090e-b643-4962-91da-e783edf7c19f", + "uiClass": "ContactSensor" + }, + { + "creationTime": 1588332894000, + "lastUpdateTime": 1588332894000, + "label": "IO (5276217#4)", + "deviceURL": "io://0814-0291-7832/5276217#4", + "shortcut": false, + "controllableName": "io:OccupancyIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "eventBased": true, + "type": "DiscreteState", + "values": ["noPersonInside", "personInside"], + "qualifiedName": "core:OccupancyState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + } + ], + "dataProperties": [], + "widgetName": "OccupancySensor", + "uiProfiles": ["OccupancyDetector"], + "uiClass": "OccupancySensor", + "qualifiedName": "io:OccupancyIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "available" + }, + { + "name": "core:OccupancyState", + "type": 3, + "value": "noPersonInside" + } + ], + "attributes": [ + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + } + ], + "available": true, + "enabled": true, + "placeOID": "dab51ec0-5b0c-4694-8389-7498f02d6ee6", + "widget": "OccupancySensor", + "type": 2, + "oid": "4a2301c2-3793-47eb-b7d9-ea73b7172f2e", + "uiClass": "OccupancySensor" + }, + { + "creationTime": 1588332894000, + "lastUpdateTime": 1588332894000, + "label": "IO (5276217#5)", + "deviceURL": "io://0814-0291-7832/5276217#5", + "shortcut": false, + "controllableName": "io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff0State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff1State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff2State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff3State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff4State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff5State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff6State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff7State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff8State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff9State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ElectricEnergyConsumptionState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + } + ], + "dataProperties": [], + "widgetName": "CumulativeElectricPowerConsumptionSensor", + "uiProfiles": ["ElectricEnergyConsumption"], + "uiClass": "ElectricitySensor", + "qualifiedName": "io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "available" + }, + { + "name": "core:ElectricEnergyConsumptionState", + "type": 1, + "value": 175000 + }, + { + "name": "core:ConsumptionTariff1State", + "type": 1, + "value": 37000 + }, + { + "name": "core:ConsumptionTariff2State", + "type": 1, + "value": 80000 + } + ], + "attributes": [ + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + }, + { + "name": "core:MeasuredValueType", + "type": 3, + "value": "core:ElectricalEnergyInWh" + } + ], + "available": true, + "enabled": true, + "placeOID": "dab51ec0-5b0c-4694-8389-7498f02d6ee6", + "widget": "CumulativeElectricPowerConsumptionSensor", + "type": 2, + "oid": "cb623839-1213-41b3-a67e-b5e0c80e9141", + "uiClass": "ElectricitySensor" + }, + { + "creationTime": 1586773220000, + "lastUpdateTime": 1586773220000, + "label": "Radiateur", + "deviceURL": "io://0814-0291-7832/6412161#1", + "shortcut": false, + "controllableName": "io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent", + "definition": { + "commands": [ + { + "commandName": "advancedRefresh", + "nparams": 1 + }, + { + "commandName": "cancelHeatingLevel", + "nparams": 1 + }, + { + "commandName": "delayedStopIdentify", + "nparams": 1 + }, + { + "commandName": "getName", + "nparams": 0 + }, + { + "commandName": "identify", + "nparams": 0 + }, + { + "commandName": "noPersonInside", + "nparams": 0 + }, + { + "commandName": "off", + "nparams": 0 + }, + { + "commandName": "personInside", + "nparams": 0 + }, + { + "commandName": "refreshComfortTemperature", + "nparams": 0 + }, + { + "commandName": "refreshDateTime", + "nparams": 0 + }, + { + "commandName": "refreshDerogatedTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshEcoTemperature", + "nparams": 0 + }, + { + "commandName": "refreshHeatingLevel", + "nparams": 0 + }, + { + "commandName": "refreshIdentifier", + "nparams": 0 + }, + { + "commandName": "refreshManufacturerName", + "nparams": 0 + }, + { + "commandName": "refreshMaximumHeatingTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshMaximumTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshOperatingMode", + "nparams": 0 + }, + { + "commandName": "refreshTargetTemperature", + "nparams": 0 + }, + { + "commandName": "refreshTemperature", + "nparams": 0 + }, + { + "commandName": "refreshTimeProgram", + "nparams": 0 + }, + { + "commandName": "setComfortTemperature", + "nparams": 1 + }, + { + "commandName": "setDateTime", + "nparams": 1 + }, + { + "commandName": "setDerogatedTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setEcoTemperature", + "nparams": 1 + }, + { + "commandName": "setHeatingLevel", + "nparams": 1 + }, + { + "commandName": "setHeatingLevelWithTimer", + "nparams": 2 + }, + { + "commandName": "setHolidays", + "nparams": 1 + }, + { + "commandName": "setHolidaysTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setName", + "nparams": 1 + }, + { + "commandName": "setOccupancyActivation", + "nparams": 1 + }, + { + "commandName": "setOccupancy", + "nparams": 1 + }, + { + "commandName": "setOpenWindowDetectionActivation", + "nparams": 1 + }, + { + "commandName": "setOperatingMode", + "nparams": 1 + }, + { + "commandName": "setPreviousTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setSchedulingType", + "nparams": 1 + }, + { + "commandName": "setTargetTemperature", + "nparams": 1 + }, + { + "commandName": "setTimeProgram", + "nparams": 1 + }, + { + "commandName": "startIdentify", + "nparams": 0 + }, + { + "commandName": "stopIdentify", + "nparams": 0 + }, + { + "commandName": "wink", + "nparams": 1 + }, + { + "commandName": "pairOneWayController", + "nparams": 2 + }, + { + "commandName": "refreshAutoProgram", + "nparams": 0 + }, + { + "commandName": "refreshControllerAddress", + "nparams": 0 + }, + { + "commandName": "refreshCumulatedLowering", + "nparams": 0 + }, + { + "commandName": "refreshCurrentWorkingRate", + "nparams": 0 + }, + { + "commandName": "refreshDeletionCancelation", + "nparams": 0 + }, + { + "commandName": "refreshEffectiveTemperatureSetpoint", + "nparams": 0 + }, + { + "commandName": "refreshLocalLeadTime", + "nparams": 0 + }, + { + "commandName": "refreshModel", + "nparams": 0 + }, + { + "commandName": "refreshNativeFunctionalLevel", + "nparams": 0 + }, + { + "commandName": "refreshPeakNotice", + "nparams": 0 + }, + { + "commandName": "refreshPeakWarning", + "nparams": 0 + }, + { + "commandName": "refreshPowerAndTension", + "nparams": 0 + }, + { + "commandName": "refreshRoomDeletionThreshold", + "nparams": 0 + }, + { + "commandName": "refreshSetpointLoweringTemperatureInProgMode", + "nparams": 0 + }, + { + "commandName": "refreshSynchronisationRequest", + "nparams": 0 + }, + { + "commandName": "refreshTemperatureProbeCalibrationOffset", + "nparams": 0 + }, + { + "commandName": "setCommunicationTest", + "nparams": 1 + }, + { + "commandName": "setDeletionCancelation", + "nparams": 1 + }, + { + "commandName": "setExpectedPresence", + "nparams": 1 + }, + { + "commandName": "setHeatingLevelForTrigger", + "nparams": 1 + }, + { + "commandName": "setNativeLevelsList", + "nparams": 1 + }, + { + "commandName": "setPeakNotice", + "nparams": 1 + }, + { + "commandName": "setPeakWarning", + "nparams": 1 + }, + { + "commandName": "setRoomDeletionThreshold", + "nparams": 1 + }, + { + "commandName": "setSetpointLoweringTemperatureInProgMode", + "nparams": 1 + }, + { + "commandName": "setTemperatureProbeCalibrationOffset", + "nparams": 1 + }, + { + "commandName": "setTwinningExit", + "nparams": 1 + }, + { + "commandName": "unpairAllOneWayControllers", + "nparams": 0 + }, + { + "commandName": "unpairOneWayController", + "nparams": 2 + } + ], + "states": [ + { + "type": "ContinuousState", + "qualifiedName": "core:ComfortRoomTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:DateTimeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:DerogatedTargetTemperatureState" + }, + { + "type": "DiscreteState", + "values": ["good", "low", "normal", "verylow"], + "qualifiedName": "core:DiscreteRSSILevelState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:EcoRoomTemperatureState" + }, + { + "type": "DiscreteState", + "values": ["off", "on"], + "qualifiedName": "core:HolidaysModeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:HolidaysTargetTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:IdentifierState" + }, + { + "type": "DataState", + "qualifiedName": "core:ManufacturerNameState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:MaximumHeatingTargetTemperatureState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:MaximumTargetTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:NameState" + }, + { + "type": "DiscreteState", + "values": ["active", "inactive"], + "qualifiedName": "core:OccupancyActivationState" + }, + { + "type": "DiscreteState", + "values": ["off", "on"], + "qualifiedName": "core:OnOffState" + }, + { + "type": "DiscreteState", + "values": ["active", "inactive"], + "qualifiedName": "core:OpenWindowDetectionActivationState" + }, + { + "type": "DiscreteState", + "values": [ + "antifreeze", + "auto", + "away", + "eco", + "frostprotection", + "manual", + "max", + "normal", + "off", + "on", + "prog", + "program", + "boost" + ], + "qualifiedName": "core:OperatingModeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:PreviousTargetTemperatureState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:PriorityLockTimerState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:RSSILevelState" + }, + { + "type": "DiscreteState", + "values": ["increase", "none", "standby"], + "qualifiedName": "core:RegulationModeState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:TargetTemperatureState" + }, + { + "type": "DataState", + "qualifiedName": "core:TimeProgramState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:VersionState" + }, + { + "type": "DataState", + "qualifiedName": "io:AutoProgramState" + }, + { + "type": "DataState", + "qualifiedName": "io:ControllerAddressState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:CumulatedLoweringState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:CurrentWorkingRateState" + }, + { + "type": "DiscreteState", + "values": ["deletion cancelation", "no deletion cancelation"], + "qualifiedName": "io:DeletionCancelationState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:EffectiveTemperatureSetpointState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:ExpectedPresenceState" + }, + { + "type": "DiscreteState", + "values": ["external", "internal"], + "qualifiedName": "io:InternalExternalSchedulingTypeState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:LocalLeadTimeState" + }, + { + "type": "DiscreteState", + "values": ["boost", "comfort", "comfort-1", "comfort-2", "eco", "frostprotection", "off", "secured"], + "qualifiedName": "io:MaximumHeatingLevelState" + }, + { + "type": "DataState", + "qualifiedName": "io:ModelState" + }, + { + "type": "DiscreteState", + "values": ["base", "medium", "top"], + "qualifiedName": "io:NativeFunctionalLevelState" + }, + { + "type": "DiscreteState", + "values": ["long peak", "no peak", "short peak"], + "qualifiedName": "io:PeakNoticeState" + }, + { + "type": "DiscreteState", + "values": ["long peak warning", "no warning", "short peak warning"], + "qualifiedName": "io:PeakWarningState" + }, + { + "type": "DataState", + "qualifiedName": "io:PowerState" + }, + { + "type": "DiscreteState", + "values": [ + "comfortLevel1", + "comfortLevel2", + "comfortLevel3", + "comfortLevel4", + "environmentProtection", + "humanProtection", + "userLevel1", + "userLevel2" + ], + "qualifiedName": "io:PriorityLockLevelState" + }, + { + "type": "DiscreteState", + "values": [ + "LSC", + "SAAC", + "SFC", + "UPS", + "externalGateway", + "localUser", + "myself", + "rain", + "security", + "temperature", + "timer", + "user", + "wind" + ], + "qualifiedName": "io:PriorityLockOriginatorState" + }, + { + "type": "DataState", + "qualifiedName": "io:RoomDeletionThresholdState" + }, + { + "type": "DiscreteState", + "values": ["kept", "lost"], + "qualifiedName": "io:RunningState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:SetpointLoweringTemperatureInProgModeState" + }, + { + "type": "DiscreteState", + "values": ["boost", "comfort", "comfort-1", "comfort-2", "eco", "frostprotection", "off", "secured"], + "qualifiedName": "io:TargetHeatingLevelState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:TemperatureProbeCalibrationOffsetState" + }, + { + "type": "DataState", + "qualifiedName": "io:TensionState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:TimerForTransitoryStateState" + }, + { + "type": "ContinuousState", + "qualifiedName": "io:UptimeState" + } + ], + "dataProperties": [ + { + "value": "500", + "qualifiedName": "core:identifyInterval" + } + ], + "widgetName": "AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint", + "uiProfiles": ["StatefulOperatingModeHeating", "OperatingModeHeating", "StatefulThermostat", "Thermostat"], + "uiClass": "HeatingSystem", + "uiClassifiers": ["emitter"], + "qualifiedName": "io:AtlanticElectricalHeaterWithAdjustableTemperatureSetpointIOComponent", + "type": "ACTUATOR" + }, + "states": [ + { + "name": "core:NameState", + "type": 3, + "value": "Radiateur" + }, + { + "name": "core:VersionState", + "type": 3, + "value": "49373431303038202020" + }, + { + "name": "core:PriorityLockTimerState", + "type": 1, + "value": 0 + }, + { + "name": "core:OnOffState", + "type": 3, + "value": "on" + }, + { + "name": "io:TargetHeatingLevelState", + "type": 3, + "value": "comfort" + }, + { + "name": "core:StatusState", + "type": 3, + "value": "unavailable" + }, + { + "name": "core:DiscreteRSSILevelState", + "type": 3, + "value": "good" + }, + { + "name": "core:RSSILevelState", + "type": 2, + "value": 82 + }, + { + "name": "core:IdentifierState", + "type": 3, + "value": "00000000" + }, + { + "name": "io:MaximumHeatingLevelState", + "type": 3, + "value": "unknown" + }, + { + "name": "io:TimerForTransitoryStateState", + "type": 1, + "value": 0 + }, + { + "name": "core:ComfortRoomTemperatureState", + "type": 1, + "value": 22 + }, + { + "name": "core:EcoRoomTemperatureState", + "type": 2, + "value": 4.5 + }, + { + "name": "core:OperatingModeState", + "type": 3, + "value": "standby" + }, + { + "name": "core:OccupancyActivationState", + "type": 3, + "value": "inactive" + }, + { + "name": "core:MaximumHeatingTargetTemperatureState", + "type": 2, + "value": 28 + }, + { + "name": "core:MaximumTargetTemperatureState", + "type": 2, + "value": 28 + }, + { + "name": "core:TargetTemperatureState", + "type": 2, + "value": 20.5 + }, + { + "name": "io:SetpointLoweringTemperatureInProgModeState", + "type": 2, + "value": 4.5 + }, + { + "name": "core:OpenWindowDetectionActivationState", + "type": 3, + "value": "inactive" + }, + { + "name": "io:InternalExternalSchedulingTypeState", + "type": 3, + "value": "internal" + }, + { + "name": "core:DateTimeState", + "type": 11, + "value": { + "month": 12, + "hour": 11, + "year": 2021, + "weekday": 3, + "day": 30, + "minute": 44, + "second": 46 + } + }, + { + "name": "io:LocalLeadTimeState", + "type": 1, + "value": 1744 + }, + { + "name": "core:RegulationModeState", + "type": 3, + "value": "increase" + }, + { + "name": "core:ManufacturerNameState", + "type": 3, + "value": "Atlantic" + }, + { + "name": "io:ModelState", + "type": 3, + "value": "AGILIA H PI-io" + }, + { + "name": "io:PowerState", + "type": 1, + "value": 750 + }, + { + "name": "io:TensionState", + "type": 1, + "value": 230 + }, + { + "name": "core:DerogatedTargetTemperatureState", + "type": 2, + "value": 0 + }, + { + "name": "io:NativeFunctionalLevelState", + "type": 3, + "value": "Top" + }, + { + "name": "io:TemperatureProbeCalibrationOffsetState", + "type": 2, + "value": 0 + }, + { + "name": "io:CurrentWorkingRateState", + "type": 2, + "value": 0 + }, + { + "name": "io:CumulatedLoweringState", + "type": 2, + "value": 0 + }, + { + "name": "io:RoomDeletionThresholdState", + "type": 3, + "value": "-2°C" + }, + { + "name": "io:EffectiveTemperatureSetpointState", + "type": 2, + "value": 0 + }, + { + "name": "io:ControllerAddressState", + "type": 1, + "value": 6412160 + }, + { + "name": "io:ExpectedPresenceState", + "type": 3, + "value": "19:30", + "lastUpdateTime": 1638202928000 + }, + { + "name": "io:AutoProgramState", + "type": 11, + "value": { + "sunday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_1", + "CONF_1", + "CONF_3_NIV1", + "CONF_2", + "CONF_NIV1", + "CONF_1", + "CONF_3_NIV1", + "CONF_2", + "CONF_1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_2", + "CONF_3_NIV1", + "CONF_2", + "CONF_1", + "CONF_2", + "CONF_3_NIV1", + "CONF_1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2" + ], + "saturday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_2", + "CONF_2", + "CONF_NIV3", + "CONF_NIV3", + "CONF_NIV1", + "CONF_2", + "CONF_1", + "CONF_NIV2", + "CONF_2", + "CONF_NIV3", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_2", + "CONF_2", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_1", + "CONF_3_NIV1", + "CONF_3_NIV1" + ], + "tuesday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_2", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV2", + "CONF_3_NIV2", + "CONF_2", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1" + ], + "wednesday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_2", + "CONF_2", + "CONF_1", + "CONF_1", + "CONF_1", + "CONF_2", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_1", + "CONF_3_NIV2", + "CONF_1", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1" + ], + "thursday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_2", + "CONF_2", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV2", + "CONF_3_NIV2", + "CONF_3_NIV2", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1" + ], + "friday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_1", + "CONF_1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1" + ], + "anticipTime": 1744, + "anticipNb": 20, + "monday": [ + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_2", + "CONF_2", + "CONF_3_NIV1", + "CONF_2", + "CONF_2", + "CONF_2", + "CONF_2", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_1", + "CONF_2", + "CONF_1", + "CONF_3_NIV2", + "CONF_3_NIV1", + "CONF_2", + "CONF_2", + "CONF_1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_3_NIV1", + "CONF_2", + "CONF_3_NIV1" + ] + } + }, + { + "name": "core:PreviousTargetTemperatureState", + "type": 2, + "value": 17 + }, + { + "name": "core:TimeProgramState", + "type": 10, + "value": [ + { + "monday": [ + { + "start": "07:00", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "tuesday": [ + { + "start": "07:00", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "wednesday": [ + { + "start": "07:00", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "thursday": [ + { + "start": "07:00", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "friday": [ + { + "start": "07:00", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "saturday": [ + { + "start": "07:00", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + }, + { + "sunday": [ + { + "start": "07:00", + "end": "20:00" + }, + { + "start": "00:00", + "end": "00:00" + }, + { + "start": "00:00", + "end": "00:00" + } + ] + } + ] + } + ], + "attributes": [ + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + } + ], + "available": false, + "enabled": true, + "placeOID": "2de0b602-9a42-48d3-9c9f-42bc192c8783", + "widget": "AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint", + "type": 1, + "oid": "29bbe178-d3e3-4322-85dd-cafc8148cf41", + "uiClass": "HeatingSystem" + }, + { + "creationTime": 1586773220000, + "lastUpdateTime": 1586773220000, + "label": "IO (6412161#2)", + "deviceURL": "io://0814-0291-7832/6412161#2", + "shortcut": false, + "controllableName": "io:TemperatureInCelciusIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:TemperatureState" + } + ], + "dataProperties": [], + "widgetName": "TemperatureSensor", + "uiProfiles": ["Temperature"], + "uiClass": "TemperatureSensor", + "qualifiedName": "io:TemperatureInCelciusIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "unavailable" + }, + { + "name": "core:TemperatureState", + "type": 2, + "value": 18.6 + } + ], + "attributes": [ + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:MeasuredValueType", + "type": 3, + "value": "core:TemperatureInCelcius" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + } + ], + "available": false, + "enabled": true, + "placeOID": "2de0b602-9a42-48d3-9c9f-42bc192c8783", + "widget": "TemperatureSensor", + "type": 2, + "oid": "0a9055f2-6748-4f7b-b6f1-e396cc13203b", + "uiClass": "TemperatureSensor" + }, + { + "creationTime": 1586773220000, + "lastUpdateTime": 1586773220000, + "label": "IO (6412161#3)", + "deviceURL": "io://0814-0291-7832/6412161#3", + "shortcut": false, + "controllableName": "io:ContactIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "type": "DiscreteState", + "values": ["closed", "open"], + "qualifiedName": "core:ContactState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + } + ], + "dataProperties": [], + "widgetName": "ContactSensor", + "uiProfiles": ["DoorContactSensor", "ContactDetector"], + "uiClass": "ContactSensor", + "qualifiedName": "io:ContactIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "unavailable" + }, + { + "name": "core:ContactState", + "type": 3, + "value": "closed" + } + ], + "attributes": [ + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + } + ], + "available": false, + "enabled": true, + "placeOID": "2de0b602-9a42-48d3-9c9f-42bc192c8783", + "widget": "ContactSensor", + "type": 2, + "oid": "73a92bd3-b831-4071-b1ff-a5f6b55cc838", + "uiClass": "ContactSensor" + }, + { + "creationTime": 1586773220000, + "lastUpdateTime": 1586773220000, + "label": "IO (6412161#4)", + "deviceURL": "io://0814-0291-7832/6412161#4", + "shortcut": false, + "controllableName": "io:OccupancyIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "eventBased": true, + "type": "DiscreteState", + "values": ["noPersonInside", "personInside"], + "qualifiedName": "core:OccupancyState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + } + ], + "dataProperties": [], + "widgetName": "OccupancySensor", + "uiProfiles": ["OccupancyDetector"], + "uiClass": "OccupancySensor", + "qualifiedName": "io:OccupancyIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "unavailable" + }, + { + "name": "core:OccupancyState", + "type": 3, + "value": "personInside" + } + ], + "attributes": [ + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + } + ], + "available": false, + "enabled": true, + "placeOID": "2de0b602-9a42-48d3-9c9f-42bc192c8783", + "widget": "OccupancySensor", + "type": 2, + "oid": "357d8eb4-7bb5-45bf-a6ab-afa7460b673a", + "uiClass": "OccupancySensor" + }, + { + "creationTime": 1586773220000, + "lastUpdateTime": 1586773220000, + "label": "IO (6412161#5)", + "deviceURL": "io://0814-0291-7832/6412161#5", + "shortcut": false, + "controllableName": "io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor", + "definition": { + "commands": [], + "states": [ + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff0State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff1State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff2State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff3State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff4State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff5State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff6State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff7State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff8State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ConsumptionTariff9State" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:ElectricEnergyConsumptionState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + } + ], + "dataProperties": [], + "widgetName": "CumulativeElectricPowerConsumptionSensor", + "uiProfiles": ["ElectricEnergyConsumption"], + "uiClass": "ElectricitySensor", + "qualifiedName": "io:CumulatedElectricalEnergyConsumptionIOSystemDeviceSensor", + "type": "SENSOR" + }, + "states": [ + { + "name": "core:StatusState", + "type": 3, + "value": "unavailable" + }, + { + "name": "core:ElectricEnergyConsumptionState", + "type": 1, + "value": 232000 + }, + { + "name": "core:ConsumptionTariff1State", + "type": 1, + "value": 25000 + }, + { + "name": "core:ConsumptionTariff2State", + "type": 1, + "value": 123000 + } + ], + "attributes": [ + { + "name": "core:Manufacturer", + "type": 3, + "value": "Atlantic Group" + }, + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "I741008" + }, + { + "name": "core:PowerSourceType", + "type": 3, + "value": "mainSupply" + }, + { + "name": "core:MeasuredValueType", + "type": 3, + "value": "core:ElectricalEnergyInWh" + } + ], + "available": false, + "enabled": true, + "placeOID": "2de0b602-9a42-48d3-9c9f-42bc192c8783", + "widget": "CumulativeElectricPowerConsumptionSensor", + "type": 2, + "oid": "d4642883-14a9-4d05-ad6c-c50e3c1448e4", + "uiClass": "ElectricitySensor" + } + ], + "zones": [], + "resellerDelegationType": "NEVER", + "oid": "26bb7fd1-15c3-4f67-a39a-93ad60009c6c", + "rootPlace": { + "creationTime": 1586773014000, + "lastUpdateTime": 1586773014000, + "label": "All House", + "type": 0, + "oid": "ebd3b36a-dd8f-4012-90c3-6ab51607e889", + "subPlaces": [ + { + "creationTime": 1586773400000, + "lastUpdateTime": 1586773400000, + "label": "Parents", + "type": 5, + "oid": "dab51ec0-5b0c-4694-8389-7498f02d6ee6", + "subPlaces": [] + }, + { + "creationTime": 1586773256000, + "lastUpdateTime": 1586773256000, + "label": "Maxime", + "type": 5, + "oid": "2de0b602-9a42-48d3-9c9f-42bc192c8783", + "subPlaces": [] + }, + { + "creationTime": 1601921676000, + "lastUpdateTime": 1612809479000, + "label": "Salle de bain", + "type": 8, + "oid": "9abb0634-9b62-476f-8a60-0a63463e011b", + "subPlaces": [] + } + ] + }, + "features": [] +} From 31ef3acc95425b0b3b53d7aec5c682e31367a905 Mon Sep 17 00:00:00 2001 From: Pochet Romuald Date: Sat, 22 Oct 2022 01:40:45 +0200 Subject: [PATCH 02/40] Add feature mode --- front/src/components/app.jsx | 8 +-- front/src/config/i18n/en.json | 34 +++++----- front/src/config/i18n/fr.json | 64 ++++++++++--------- .../all/overkiz/OverkizDeviceBox.jsx | 14 ---- .../integration/all/overkiz/OverkizPage.jsx | 4 +- .../all/overkiz/device-page/DeviceTab.jsx | 4 +- .../all/overkiz/device-page/EmptyState.jsx | 2 +- .../all/overkiz/discover-page/DiscoverTab.jsx | 2 +- front/src/utils/consts.js | 1 + server/lib/device/device.setupPoll.js | 15 ++--- server/services/overkiz/README.md | 3 + server/services/overkiz/index.js | 16 ++++- .../overkiz/lib/commands/overkiz.connect.js | 3 + .../lib/commands/overkiz.disconnect.js | 19 ++++++ .../lib/commands/overkiz.getDevicesStates.js | 7 +- .../lib/commands/overkiz.getOverkizDevices.js | 4 +- .../lib/commands/overkiz.sendCommand.js | 9 +-- .../commands/overkiz.syncOverkizDevices.js | 19 ++---- server/services/overkiz/lib/index.js | 4 ++ server/services/overkiz/lib/overkiz.util.js | 22 ++++++- server/services/overkiz/package-lock.json | 13 ++++ server/services/overkiz/package.json | 1 + server/utils/constants.js | 9 +++ 23 files changed, 169 insertions(+), 108 deletions(-) create mode 100644 server/services/overkiz/README.md create mode 100644 server/services/overkiz/lib/commands/overkiz.disconnect.js diff --git a/front/src/components/app.jsx b/front/src/components/app.jsx index d277560d1a..df2b551c8c 100644 --- a/front/src/components/app.jsx +++ b/front/src/components/app.jsx @@ -242,10 +242,10 @@ const AppRouter = connect( - - - - + + + + diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index 09620fdd9c..6fdeedc527 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -1075,7 +1075,8 @@ } }, "overkiz": { - "title": "", + "title": "Overkiz", + "description": "Control your Overkiz devices.", "deviceTab": "", "discoverTab": "", "discoverDeviceDescr": "", @@ -1101,23 +1102,23 @@ "setupPageLink": "" }, "discover": { - "title": "", - "scan": "", + "title": "Overkiz devices in Gladys", + "scan": "Search devices", "description": "", - "noDeviceFound": "" + "noDeviceFound": "No Overkiz device found." }, "setup": { - "title": "", - "overkizDescription": "", - "error": "", - "connecting": "", - "connected": "", - "connectionError": "", - "userLabel": "", - "userPlaceholder": "", - "passwordLabel": "", - "passwordPlaceholder": "", - "saveLabel": "" + "title": "Overkiz configuration", + "overkizDescription": "You can connect Gladys to your Overkiz cloud account to command the associated devices.", + "userLabel": "Username", + "userPlaceholder": "Enter Overkiz username", + "passwordLabel": "Password", + "passwordPlaceholder": "Enter Overkiz password", + "saveLabel": "Save configuration", + "error": "An error occured while saving configuration.", + "connecting": "Configuration saved. Now connecting to your Overkiz cloud account...", + "connected": "Connected to the Overkiz cloud account with success !", + "connectionError": "Error while connecting, please check your configuration." } } }, @@ -2160,7 +2161,8 @@ }, "thermostat": { "shortCategoryName": "Thermostat", - "target-temperature": "Thermostat Temperature" + "target-temperature": "Thermostat Temperature", + "mode": "Level" }, "unknown": { "shortCategoryName": "Unknown", diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index 55b560db49..1dca07872e 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -1075,49 +1075,50 @@ } }, "overkiz": { - "title": "", - "deviceTab": "", - "discoverTab": "", + "title": "Overkiz", + "description": "Contrôler vos appareils Overkiz.", + "deviceTab": "Appareils", + "discoverTab": "Découverte", "discoverDeviceDescr": "", - "setupTab": "", + "setupTab": "Configuration", "device": { "title": "", "search": "", - "noDeviceFound": "", - "nameLabel": "", - "namePlaceholder": "", - "modelLabel": "", - "roomLabel": "", + "noDeviceFound": "Aucun périphérique Overkiz détecté.", + "nameLabel": "Nom de l'appareil", + "namePlaceholder": "Entrez le nom de votre appareil", + "modelLabel": "Modèle", + "roomLabel": "Pièce", + "saveButton": "Sauvegarder", + "updateButton": "Mettre à jour", + "alreadyCreatedButton": "Déjà créé", + "deleteButton": "Supprimer", "featuresLabel": "", - "alreadyCreatedButton": "", - "updateButton": "", - "saveButton": "", - "deleteButton": "", "unmanagedModelButton": "", "editButton": "" }, "status": { - "notConnected": "", - "setupPageLink": "" + "notConnected": "Gladys n'a pas réussi à se connecter au compte cloud Overkiz, plus d'informations sur la ", + "setupPageLink": "page de configuration Overkiz." }, "discover": { - "title": "", - "scan": "", - "description": "", - "noDeviceFound": "" + "title": "Découverte Overkiz", + "scan": "Rechercher", + "description": "Les appareils Overkiz sont automatiquement découverts. Vos appareils Overkiz doivent être ajoutés à votre compte cloud Overkiz avant.", + "noDeviceFound": "Aucun périphérique Overkiz détecté." }, "setup": { - "title": "", - "overkizDescription": "", - "error": "", - "connecting": "", - "connected": "", - "connectionError": "", - "userLabel": "", - "userPlaceholder": "", - "passwordLabel": "", - "passwordPlaceholder": "", - "saveLabel": "" + "title": "Configuration Overkiz", + "overkizDescription": "Vous pouvez connecter Gladys à votre compte cloud Overkiz pour commander les appareils associés.", + "error": "Une erreur s'est produite lors de la sauvegarde de la configuration.", + "connecting": "Configuration sauvegardée. Connexion à votre compte cloud Overkiz...", + "connected": "Connexion réussie au compte cloud Overkiz !", + "connectionError": "Erreur lors de la connexion, veuillez vérifier votre configuration.", + "userLabel": "Nom d'utilisateur", + "userPlaceholder": "Entrez le nom d'utilisateur Overkiz", + "passwordLabel": "Mot de passe", + "passwordPlaceholder": "Entrez le mot de passe utilisateur Overkiz", + "saveLabel": "Enregistrer" } } }, @@ -2160,7 +2161,8 @@ }, "thermostat": { "shortCategoryName": "Thermostat", - "target-temperature": "Température de consigne" + "target-temperature": "Température de consigne", + "mode": "Mode" }, "unknown": { "shortCategoryName": "Inconnu", diff --git a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx index 4e3bb94331..52e214e6bc 100644 --- a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx +++ b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx @@ -178,12 +178,6 @@ class OverkizDeviceBox extends Component { )} - {validModel && props.saveButton && ( - - )} - {validModel && props.deleteButton && ( )} - - {validModel && props.editButton && ( - - - - )} diff --git a/front/src/routes/integration/all/overkiz/OverkizPage.jsx b/front/src/routes/integration/all/overkiz/OverkizPage.jsx index 0b15f10847..ec7ba95f94 100644 --- a/front/src/routes/integration/all/overkiz/OverkizPage.jsx +++ b/front/src/routes/integration/all/overkiz/OverkizPage.jsx @@ -25,7 +25,7 @@ const OverkizPage = ({ children }) => ( @@ -36,7 +36,7 @@ const OverkizPage = ({ children }) => ( diff --git a/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx b/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx index c80be6d3dc..406d6c55da 100644 --- a/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx +++ b/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx @@ -51,10 +51,8 @@ const DeviceTab = ({ children, ...props }) => ( (
- + diff --git a/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx b/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx index a675e97422..9896ae4430 100644 --- a/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx +++ b/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx @@ -32,7 +32,7 @@ const DeviceTab = ({ children, ...props }) => ( {props.errorLoading && (

- +

diff --git a/front/src/utils/consts.js b/front/src/utils/consts.js index 4811d30cb6..e8e3df3906 100644 --- a/front/src/utils/consts.js +++ b/front/src/utils/consts.js @@ -269,6 +269,7 @@ export const DeviceFeatureCategoriesIcon = { [DEVICE_FEATURE_TYPES.DATARATE.RATE]: 'activity' }, [DEVICE_FEATURE_CATEGORIES.THERMOSTAT]: { + [DEVICE_FEATURE_TYPES.THERMOSTAT.MODE]: 'bar-chart', [DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE]: 'thermometer' }, [DEVICE_FEATURE_CATEGORIES.UNKNOWN]: { diff --git a/server/lib/device/device.setupPoll.js b/server/lib/device/device.setupPoll.js index 3d6408904c..04e07e8d16 100644 --- a/server/lib/device/device.setupPoll.js +++ b/server/lib/device/device.setupPoll.js @@ -1,4 +1,4 @@ -const { DEVICE_POLL_FREQUENCIES } = require('../../utils/constants'); +const { DEVICE_POLL_FREQUENCIES_LIST } = require('../../utils/constants'); /** * @description Setup poll setInterval @@ -6,16 +6,9 @@ const { DEVICE_POLL_FREQUENCIES } = require('../../utils/constants'); * setupPoll(); */ function setupPoll() { - // poll devices who need to be polled every minutes - setInterval(this.pollAll(DEVICE_POLL_FREQUENCIES.EVERY_MINUTES), DEVICE_POLL_FREQUENCIES.EVERY_MINUTES); - // poll devices who need to be polled every 30 seconds - setInterval(this.pollAll(DEVICE_POLL_FREQUENCIES.EVERY_30_SECONDS), DEVICE_POLL_FREQUENCIES.EVERY_30_SECONDS); - // poll devices who need to be polled every 10 seconds - setInterval(this.pollAll(DEVICE_POLL_FREQUENCIES.EVERY_10_SECONDS), DEVICE_POLL_FREQUENCIES.EVERY_10_SECONDS); - // poll devices who need to be polled every 2 seconds - setInterval(this.pollAll(DEVICE_POLL_FREQUENCIES.EVERY_2_SECONDS), DEVICE_POLL_FREQUENCIES.EVERY_2_SECONDS); - // poll devices who need to be polled every 1 seconds - setInterval(this.pollAll(DEVICE_POLL_FREQUENCIES.EVERY_SECONDS), DEVICE_POLL_FREQUENCIES.EVERY_SECONDS); + DEVICE_POLL_FREQUENCIES_LIST.forEach(pollFrequency => { + setInterval(this.pollAll(pollFrequency), pollFrequency); + }); } module.exports = { diff --git a/server/services/overkiz/README.md b/server/services/overkiz/README.md new file mode 100644 index 0000000000..87760d38c3 --- /dev/null +++ b/server/services/overkiz/README.md @@ -0,0 +1,3 @@ +# Overkiz + +[API](https://www.overkiz.com/produit/bibliotheque-dapi/) \ No newline at end of file diff --git a/server/services/overkiz/index.js b/server/services/overkiz/index.js index 610b575fb3..5771e874d3 100644 --- a/server/services/overkiz/index.js +++ b/server/services/overkiz/index.js @@ -28,8 +28,6 @@ module.exports = function OverkizService(gladys, serviceId) { overkizHandler.overkizType = overkizType; await overkizHandler.connect(); - - overkizHandler.syncOverkizDevices(); } /** @@ -40,11 +38,25 @@ module.exports = function OverkizService(gladys, serviceId) { */ async function stop() { logger.info('Stopping Overkiz service'); + + await overkizHandler.disconnect(); + } + + /** + * @public + * @description Get info if the service is used. + * @returns {Promise} Returns true if the service is used. + * @example + * gladys.services.overkiz.isUsed(); + */ + async function isUsed() { + return true; } return Object.freeze({ start, stop, + isUsed, device: overkizHandler, controllers: OverkizController(overkizHandler), }); diff --git a/server/services/overkiz/lib/commands/overkiz.connect.js b/server/services/overkiz/lib/commands/overkiz.connect.js index b1492fe2fb..9535177231 100644 --- a/server/services/overkiz/lib/commands/overkiz.connect.js +++ b/server/services/overkiz/lib/commands/overkiz.connect.js @@ -83,6 +83,9 @@ async function connect() { type: WEBSOCKET_MESSAGE_TYPES.OVERKIZ.CONNECTED, payload: {}, }); + + this.syncOverkizDevices(); + // this.updateDevicesJob = this.cron.schedule('0 */5 * * * *', this.syncOverkizDevices.bind(this)); } module.exports = { diff --git a/server/services/overkiz/lib/commands/overkiz.disconnect.js b/server/services/overkiz/lib/commands/overkiz.disconnect.js new file mode 100644 index 0000000000..6692520aa0 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.disconnect.js @@ -0,0 +1,19 @@ +const logger = require('../../../../utils/logger'); + +/** + * @description Disconnect to OverKiz server. + * @returns {Promise} Return Object of informations. + * @example + * overkiz.disconnect(); + */ +async function disconnect() { + logger.info(`Overkiz : Disonnecting Overkiz...`); + + if(this.updateDevicesJob) { + this.updateDevicesJob.stop(); + } +} + +module.exports = { + disconnect, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js index 0120cdeec4..7f37010bcd 100644 --- a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js +++ b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js @@ -39,9 +39,9 @@ async function getDevicesStates(device) { }, { retries: 5, - onRetry: (err, num) => { + onRetry: async (err, num) => { if (err.response && err.response.status === 401) { - connect.bind(this)(); + await connect.bind(this)(); logger.info(`Overkiz : Connecting Overkiz server...`); } else { throw err; @@ -50,10 +50,9 @@ async function getDevicesStates(device) { }, ); - device.states = response.data; logger.info(`Overkiz : Get new device states: ${deviceURL}`); - device.states.forEach((state) => { + response.data.forEach((state) => { const deviceFeatureExternalId = getDeviceFeatureExternalId({ deviceURL }, state.name); const newValueUnbind = unbindValue(device, state.name, state.value); const deviceFeature = this.gladys.stateManager.get('deviceFeatureByExternalId', deviceFeatureExternalId); diff --git a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js index 422d980fe4..bb73bc69d9 100644 --- a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js +++ b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js @@ -49,7 +49,7 @@ async function getOverkizDevices() { ready: node.available && node.enabled, rawOverkizDevice: node, should_poll: true, - poll_frequency: DEVICE_POLL_FREQUENCIES.EVERY_10_MINUTES, + poll_frequency: DEVICE_POLL_FREQUENCIES.EVERY_5_MINUTES, features: [], params: [ { @@ -86,7 +86,7 @@ async function getOverkizDevices() { selector: `overkiz-${node.deviceURL}-${node.uiClass}-${DEVICE_STATES.HEATING_LEVEL_STATE}`, external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.HEATING_LEVEL_STATE), category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, - type: DEVICE_FEATURE_TYPES.HEATER.LEVEL, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.MODE, read_only: false, has_feedback: true, min: 0, diff --git a/server/services/overkiz/lib/commands/overkiz.sendCommand.js b/server/services/overkiz/lib/commands/overkiz.sendCommand.js index bdb69e8f6e..9ad7216fbd 100644 --- a/server/services/overkiz/lib/commands/overkiz.sendCommand.js +++ b/server/services/overkiz/lib/commands/overkiz.sendCommand.js @@ -30,9 +30,9 @@ async function getExecutionState(execId) { }, { retries: 5, - onRetry: (err, num) => { + onRetry: async (err, num) => { if (err.response && err.response.status === 401) { - connect.bind(this)(); + await connect.bind(this)(); logger.info(`Overkiz : Connecting Overkiz server...`); } else { throw err; @@ -87,9 +87,9 @@ async function sendCommand(command, deviceURL, data) { }, { retries: 5, - onRetry: (err, num) => { + onRetry: async (err, num) => { if (err.response && err.response.status === 401) { - connect.bind(this)(); + await connect.bind(this)(); logger.info(`Overkiz : Connecting Overkiz server...`); } else { throw err; @@ -120,6 +120,7 @@ async function sendCommand(command, deviceURL, data) { execResponse = await getExecutionState.bind(this)(execId); const { state4 } = execResponse.data; await sleep(500); // Wait 2000 ms + logger.debug(state4); } diff --git a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js index 710eeae748..26e035f5f3 100644 --- a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js +++ b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js @@ -3,6 +3,7 @@ const retry = require('async-retry'); const logger = require('../../../../utils/logger'); const { updateGatewayState } = require('../overkiz.util'); +const { updateDevicesState } = require('../overkiz.util'); const { connect } = require('./overkiz.connect'); const { ServiceNotConfiguredError } = require('../../../../utils/coreErrors'); @@ -17,6 +18,7 @@ async function syncOverkizDevices() { throw new ServiceNotConfiguredError('OVERKIZ_NOT_CONNECTED'); } logger.debug(`Overkiz : Starting discovery`); + this.scanInProgress = true; const response = await retry( async (bail) => { @@ -35,9 +37,9 @@ async function syncOverkizDevices() { }, { retries: 5, - onRetry: (err, num) => { + onRetry: async (err, num) => { if (err.response && err.response.status === 401) { - connect.bind(this)(); + await connect.bind(this)(); logger.info(`Overkiz : Connecting Overkiz server...`); } else { throw err; @@ -46,18 +48,11 @@ async function syncOverkizDevices() { }, ); - this.devices = {}; - response.data.devices.forEach((device) => { - const placeObj = response.data.rootPlace.subPlaces.find((place) => place.oid === device.placeOID); - if (placeObj) { - device.place = placeObj.label; - } - this.devices[device.oid] = device; - }); + updateGatewayState.bind(this)(response.data.gateways); - updateGatewayState(response.data.gateways); + updateDevicesState.bind(this)(response.data.devices, response.data.rootPlace); - return this.devices; + this.scanInProgress = true; } module.exports = { diff --git a/server/services/overkiz/lib/index.js b/server/services/overkiz/lib/index.js index 4e5735af95..7a1f7c8d49 100644 --- a/server/services/overkiz/lib/index.js +++ b/server/services/overkiz/lib/index.js @@ -1,7 +1,9 @@ const Bottleneck = require('bottleneck/es5'); +const cron = require('node-cron'); const { enableDiscovery, disableDiscovery, config } = require('./commands/overkiz.config'); const { connect } = require('./commands/overkiz.connect'); +const { disconnect } = require('./commands/overkiz.disconnect'); const { getDevicesStates } = require('./commands/overkiz.getDevicesStates'); const { getOverkizDevices } = require('./commands/overkiz.getOverkizDevices'); const { setValue } = require('./commands/overkiz.setValue'); @@ -22,12 +24,14 @@ const OverkizHandler = function OverkizHandler(gladys, serviceId) { this.gladys = gladys; this.serviceId = serviceId; this.eventManager = gladys.event; + this.cron = cron; this.devices = {}; this.connected = false; this.scanInProgress = false; }; OverkizHandler.prototype.connect = connect; +OverkizHandler.prototype.disconnect = disconnect; OverkizHandler.prototype.syncOverkizDevices = syncOverkizDevices; OverkizHandler.prototype.getOverkizDevices = getOverkizDevices; OverkizHandler.prototype.poll = pollLimiter.wrap(getDevicesStates); diff --git a/server/services/overkiz/lib/overkiz.util.js b/server/services/overkiz/lib/overkiz.util.js index cd1ec2458f..6119b29463 100644 --- a/server/services/overkiz/lib/overkiz.util.js +++ b/server/services/overkiz/lib/overkiz.util.js @@ -1,7 +1,7 @@ const logger = require('../../../utils/logger'); /** - * @description Update Gatway State. + * @description Update Gateway State. * @param {Object} gateways - List of gateways. * @example * overkiz.updateGatewayState(); @@ -14,6 +14,26 @@ function updateGatewayState(gateways) { // TODO send event } +/** + * @description Update Devices State. + * @param {Object} devices - Devices. + * @param {Object} rootPlace - RootPlace. + * @example + * overkiz.updateDevicesState(devices, rootPlace); + */ +function updateDevicesState(devices, rootPlace) { + logger.debug('UpdateDevicesState'); + + devices.forEach((device) => { + const placeObj = rootPlace.subPlaces.find((place) => place.oid === device.placeOID); + if (placeObj) { + device.place = placeObj.label; + } + this.devices[device.oid] = device; + }); +} + module.exports = { updateGatewayState, + updateDevicesState, }; diff --git a/server/services/overkiz/package-lock.json b/server/services/overkiz/package-lock.json index eef42ba840..588d17480d 100644 --- a/server/services/overkiz/package-lock.json +++ b/server/services/overkiz/package-lock.json @@ -34,6 +34,14 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" }, + "node-cron": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz", + "integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==", + "requires": { + "uuid": "8.3.2" + } + }, "retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", @@ -43,6 +51,11 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/sleep-promise/-/sleep-promise-9.1.0.tgz", "integrity": "sha512-UHYzVpz9Xn8b+jikYSD6bqvf754xL2uBUzDFwiU6NcdZeifPr6UfgU43xpkPu67VMS88+TI2PSI7Eohgqf2fKA==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" } } } diff --git a/server/services/overkiz/package.json b/server/services/overkiz/package.json index 6460d8cd47..0b564c5f54 100644 --- a/server/services/overkiz/package.json +++ b/server/services/overkiz/package.json @@ -17,6 +17,7 @@ "axios": "^0.21.1", "bluebird": "^3.7.0", "bottleneck": "^2.19.5", + "node-cron": "^3.0.2", "sleep-promise": "^9.1.0" } } diff --git a/server/utils/constants.js b/server/utils/constants.js index a2e4a7c6f9..be4f115fb6 100644 --- a/server/utils/constants.js +++ b/server/utils/constants.js @@ -487,6 +487,7 @@ const DEVICE_FEATURE_TYPES = { }, THERMOSTAT: { TARGET_TEMPERATURE: 'target-temperature', + MODE: 'mode', }, }; @@ -695,6 +696,8 @@ const ACTIONS_STATUS = { }; const DEVICE_POLL_FREQUENCIES = { + EVERY_10_MINUTES: 10 * 60 * 1000, + EVERY_5_MINUTES: 5 * 60 * 1000, EVERY_MINUTES: 60 * 1000, EVERY_30_SECONDS: 30 * 1000, EVERY_10_SECONDS: 10 * 1000, @@ -781,6 +784,12 @@ const WEBSOCKET_MESSAGE_TYPES = { LEARN_MODE: 'broadlink.learn', SEND_MODE: 'broadlink.send', }, + OVERKIZ: { + CONNECTED: 'overkiz.connected', + NEW_DEVICE: 'overkiz.new-device', + UPDATE_DEVICE: 'overkiz.update-device', + ERROR: 'overkiz.error', + }, }; const DASHBOARD_TYPE = { From b072e1996f960507b32126c9d74772001e64ec0c Mon Sep 17 00:00:00 2001 From: Pochet Romuald Date: Tue, 25 Oct 2022 22:20:01 +0200 Subject: [PATCH 03/40] Mode feature --- .../boxs/device-in-room/DeviceRow.jsx | 4 +- .../boxs/device-in-room/EditDeviceInRoom.jsx | 3 +- .../ThermostatModeDeviceFeature.jsx | 61 +++++++++++++++++++ front/src/config/i18n/en.json | 5 +- front/src/config/i18n/fr.json | 5 +- .../lib/commands/overkiz.getDevicesStates.js | 13 ++-- .../lib/commands/overkiz.getOverkizDevices.js | 1 + server/utils/constants.js | 10 +++ 8 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx diff --git a/front/src/components/boxs/device-in-room/DeviceRow.jsx b/front/src/components/boxs/device-in-room/DeviceRow.jsx index b2471aa82e..bca62a7e5d 100644 --- a/front/src/components/boxs/device-in-room/DeviceRow.jsx +++ b/front/src/components/boxs/device-in-room/DeviceRow.jsx @@ -9,6 +9,7 @@ import MultiLevelDeviceFeature from './device-features/MultiLevelDeviceFeature'; import NumberDeviceFeature from './device-features/NumberDeviceFeature'; import CoverDeviceFeature from './device-features/CoverDeviceFeature'; import ThermostatDeviceFeature from './device-features/ThermostatDeviceFeature'; +import ThermostatModeDeviceFeature from './device-features/ThermostatModeDeviceFeature'; const ROW_TYPE_BY_FEATURE_TYPE = { [DEVICE_FEATURE_TYPES.LIGHT.BINARY]: BinaryDeviceFeature, @@ -22,7 +23,8 @@ const ROW_TYPE_BY_FEATURE_TYPE = { [DEVICE_FEATURE_TYPES.SHUTTER.POSITION]: MultiLevelDeviceFeature, [DEVICE_FEATURE_TYPES.CURTAIN.STATE]: CoverDeviceFeature, [DEVICE_FEATURE_TYPES.CURTAIN.POSITION]: MultiLevelDeviceFeature, - [DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE]: ThermostatDeviceFeature + [DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE]: ThermostatDeviceFeature, + [DEVICE_FEATURE_TYPES.THERMOSTAT.MODE]: ThermostatModeDeviceFeature }; const DeviceRow = ({ children, ...props }) => { diff --git a/front/src/components/boxs/device-in-room/EditDeviceInRoom.jsx b/front/src/components/boxs/device-in-room/EditDeviceInRoom.jsx index ea8828c135..003395f09c 100644 --- a/front/src/components/boxs/device-in-room/EditDeviceInRoom.jsx +++ b/front/src/components/boxs/device-in-room/EditDeviceInRoom.jsx @@ -19,7 +19,8 @@ const SUPPORTED_FEATURE_TYPES = [ DEVICE_FEATURE_TYPES.TELEVISION.VOLUME, DEVICE_FEATURE_TYPES.SHUTTER.POSITION, DEVICE_FEATURE_TYPES.SHUTTER.STATE, - DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE + DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, + DEVICE_FEATURE_TYPES.THERMOSTAT.MODE ]; @connect('httpClient', {}) diff --git a/front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx b/front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx new file mode 100644 index 0000000000..6c2128337b --- /dev/null +++ b/front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx @@ -0,0 +1,61 @@ +import { getDeviceName } from './utils'; +import { Text } from 'preact-i18n'; +import cx from 'classnames'; + +import { THERMOSTAT_MODE } from '../../../../../../server/utils/constants'; + +const ThermostatModeDeviceType = ({ children, ...props }) => { + const { device, deviceFeature } = props; + const { category, type, last_value: lastValue } = deviceFeature; + + function updateValue(value) { + props.updateValue( + props.x, + props.y, + device, + deviceFeature, + props.deviceIndex, + props.deviceFeatureIndex, + value, + lastValue + ); + } + + function setOffMode() { + updateValue(THERMOSTAT_MODE.OFF); + } + function setEcoMode() { + updateValue(THERMOSTAT_MODE.ECO); + } + function setComfortMode() { + updateValue(THERMOSTAT_MODE.COMFORT); + } + + return ( + + + + + {getDeviceName(props.device, props.deviceFeature)} + + + + + + + ); +}; + +export default ThermostatModeDeviceType; diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index 6fdeedc527..146ef2c0fa 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -230,7 +230,10 @@ "deviceTitle": "{{name}} - {{type}}", "noDevices": "Looks you don't have any devices in your house!
Define your device in the integration page.", "addButton": "+", - "substractButton": "-" + "substractButton": "-", + "offMode": "Off", + "ecoMode": "Eco", + "comfortMode": "Comfort" }, "temperatureInRoom": { "editRoomLabel": "Select the room you want to display here.", diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index 1dca07872e..b4ae7cef4c 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -230,7 +230,10 @@ "deviceTitle": "{{name}} - {{type}}", "noDevices": "Vous n'avez pas d'appareil dans votre maison !
Définissez votre appareil dans la page de l'intégration.", "addButton": "+", - "substractButton": "-" + "substractButton": "-", + "offMode": "Off", + "ecoMode": "Eco", + "comfortMode": "Comfort" }, "temperatureInRoom": { "editRoomLabel": "Sélectionnez la pièce que vous souhaitez afficher ici.", diff --git a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js index 7f37010bcd..187ee86e35 100644 --- a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js +++ b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js @@ -4,7 +4,7 @@ const logger = require('../../../../utils/logger'); const { getDeviceFeatureExternalId, getNodeStateInfoByExternalId } = require('../utils/overkiz.externalId'); const { unbindValue } = require('../utils/overkiz.bindValue'); const { connect } = require('./overkiz.connect'); -const { EVENTS } = require('../../../../utils/constants'); +const { EVENTS, DEVICE_FEATURE_CATEGORIES } = require('../../../../utils/constants'); /** * @description Update device states. @@ -57,10 +57,13 @@ async function getDevicesStates(device) { const newValueUnbind = unbindValue(device, state.name, state.value); const deviceFeature = this.gladys.stateManager.get('deviceFeatureByExternalId', deviceFeatureExternalId); if (deviceFeature) { - this.eventManager.emit(EVENTS.DEVICE.NEW_STATE, { - device_feature_external_id: deviceFeatureExternalId, - state: newValueUnbind, - }); + if(deviceFeature.category !== DEVICE_FEATURE_CATEGORIES.PRESENCE_SENSOR || + newValueUnbind !== 0) { + this.eventManager.emit(EVENTS.DEVICE.NEW_STATE, { + device_feature_external_id: deviceFeatureExternalId, + state: newValueUnbind, + }); + } } }); }); diff --git a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js index bb73bc69d9..cd675a33c9 100644 --- a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js +++ b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js @@ -152,6 +152,7 @@ async function getOverkizDevices() { }), ); } + return newDevice; }); diff --git a/server/utils/constants.js b/server/utils/constants.js index be4f115fb6..c6b7c56f23 100644 --- a/server/utils/constants.js +++ b/server/utils/constants.js @@ -45,6 +45,15 @@ const SERVICE_STATUS = { ERROR: 'ERROR', }; +const THERMOSTAT_MODE = { + OFF: 0, + FROST_PROTECTION: 1, + ECO: 2, + COMFORT_2: 3, + COMFORT_1: 4, + COMFORT: 5, +}; + const SYSTEM_VARIABLE_NAMES = { DEVICE_STATE_HISTORY_IN_DAYS: 'DEVICE_STATE_HISTORY_IN_DAYS', DEVICE_STATE_MONTHLY_AGGREGATES_RETENTION_IN_DAYS: 'DEVICE_STATE_MONTHLY_AGGREGATES_RETENTION_IN_DAYS', @@ -893,6 +902,7 @@ module.exports.ACTIONS_STATUS = ACTIONS_STATUS; module.exports.USER_ROLE = USER_ROLE; module.exports.AVAILABLE_LANGUAGES = AVAILABLE_LANGUAGES; module.exports.SESSION_TOKEN_TYPES = SESSION_TOKEN_TYPES; +module.exports.THERMOSTAT_MODE = THERMOSTAT_MODE; module.exports.EVENT_LIST = EVENT_LIST; module.exports.LIFE_EVENT_LIST = LIFE_EVENT_LIST; From 72254e88f436c108518da8d2763a8cf7a4c8b0b7 Mon Sep 17 00:00:00 2001 From: Pochet Romuald Date: Tue, 25 Oct 2022 22:41:42 +0200 Subject: [PATCH 04/40] ECO temperature --- .../services/overkiz/lib/commands/overkiz.syncOverkizDevices.js | 2 +- server/services/overkiz/lib/utils/overkiz.constants.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js index 26e035f5f3..d5b307b0f5 100644 --- a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js +++ b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js @@ -52,7 +52,7 @@ async function syncOverkizDevices() { updateDevicesState.bind(this)(response.data.devices, response.data.rootPlace); - this.scanInProgress = true; + this.scanInProgress = false; } module.exports = { diff --git a/server/services/overkiz/lib/utils/overkiz.constants.js b/server/services/overkiz/lib/utils/overkiz.constants.js index c4a28daeb0..fb19826ca8 100644 --- a/server/services/overkiz/lib/utils/overkiz.constants.js +++ b/server/services/overkiz/lib/utils/overkiz.constants.js @@ -110,7 +110,7 @@ const DEVICE_STATES = { OCCUPANCY_STATE: 'core:OccupancyState', TEMPERATURE_STATE: 'core:TemperatureState', COMFORT_TEMPERATURE_STATE: 'core:ComfortRoomTemperatureState', - ECO_TEMPERATURE_STATE: 'core:EcoRoomTemperatureState', + ECO_TEMPERATURE_STATE: 'io:EffectiveTemperatureSetpointState', // 'core:EcoRoomTemperatureState', ON_OFF_STATE: 'core:OnOffState', ELECTRIC_ENERGY_CONSUMTION_STATE: 'core:ElectricEnergyConsumptionState', }; From f7630b389a66b179e96d356d41abb7e209cc5510 Mon Sep 17 00:00:00 2001 From: Pochet Romuald Date: Sun, 8 Jan 2023 19:30:06 +0100 Subject: [PATCH 05/40] Review --- .../ThermostatModeDeviceFeature.jsx | 10 +- front/src/config/i18n/en.json | 8 +- front/src/config/i18n/fr.json | 4 +- .../all/overkiz/OverkizDeviceBox.jsx | 60 +- .../all/overkiz/device-page/DeviceTab.jsx | 7 +- .../all/overkiz/discover-page/DiscoverTab.jsx | 6 +- .../overkiz/lib/commands/overkiz.connect.js | 66 +- .../lib/commands/overkiz.getDevicesStates.js | 52 +- .../lib/commands/overkiz.getOverkizDevices.js | 68 +- .../lib/commands/overkiz.sendCommand.js | 86 +- .../commands/overkiz.syncOverkizDevices.js | 77 +- server/services/overkiz/lib/overkiz.util.js | 39 - .../overkiz/lib/utils/overkiz.constants.js | 6 + .../overkiz/lib/utils/overkiz.externalId.js | 8 +- server/services/overkiz/package-lock.json | 943 +++++++++++++++++- server/services/overkiz/package.json | 2 +- 16 files changed, 1139 insertions(+), 303 deletions(-) delete mode 100644 server/services/overkiz/lib/overkiz.util.js diff --git a/front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx b/front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx index 6c2128337b..714da81200 100644 --- a/front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx +++ b/front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx @@ -1,12 +1,12 @@ -import { getDeviceName } from './utils'; import { Text } from 'preact-i18n'; import cx from 'classnames'; +import { getDeviceName } from '../../../../utils/device'; import { THERMOSTAT_MODE } from '../../../../../../server/utils/constants'; const ThermostatModeDeviceType = ({ children, ...props }) => { const { device, deviceFeature } = props; - const { category, type, last_value: lastValue } = deviceFeature; + const { last_value: lastValue } = deviceFeature; function updateValue(value) { props.updateValue( @@ -41,17 +41,17 @@ const ThermostatModeDeviceType = ({ children, ...props }) => { diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index 42e68867a0..d4f1a8651a 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -1066,11 +1066,9 @@ "modelLabel": "", "roomLabel": "", "featuresLabel": "", - "alreadyCreatedButton": "", - "updateButton": "", - "saveButton": "", - "deleteButton": "", - "unmanagedModelButton": "", + "createButton": "Save", + "updateButton": "Update", + "deleteButton": "Delete", "editButton": "" }, "status": { diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index 870c6e2706..eb8427b7f4 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -1065,12 +1065,10 @@ "namePlaceholder": "Entrez le nom de votre appareil", "modelLabel": "Modèle", "roomLabel": "Pièce", - "saveButton": "Sauvegarder", + "createButton": "Sauvegarder", "updateButton": "Mettre à jour", - "alreadyCreatedButton": "Déjà créé", "deleteButton": "Supprimer", "featuresLabel": "", - "unmanagedModelButton": "", "editButton": "" }, "status": { diff --git a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx index 52e214e6bc..9ac1d6ddd0 100644 --- a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx +++ b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx @@ -4,7 +4,6 @@ import cx from 'classnames'; import { DeviceFeatureCategoriesIcon } from '../../../../utils/consts'; import { DEVICE_FIRMWARE, DEVICE_ONLINE } from '../../../../../../server/services/overkiz/lib/utils/overkiz.constants'; import get from 'get-value'; -import { Link } from 'preact-router'; class OverkizDeviceBox extends Component { updateName = e => { @@ -54,7 +53,6 @@ class OverkizDeviceBox extends Component { }; render({ deviceIndex, device, housesWithRooms, editable, ...props }, { loading, errorMessage }) { - const validModel = device.features && device.features.length > 0; const online = device.params.find(param => param.name === DEVICE_ONLINE).value === '1'; const firmware = device.params.find(param => param.name === DEVICE_FIRMWARE).value; @@ -99,7 +97,7 @@ class OverkizDeviceBox extends Component { onInput={this.updateName} class="form-control" placeholder={} - disabled={!editable || !validModel} + disabled={!editable} /> @@ -117,7 +115,7 @@ class OverkizDeviceBox extends Component { /> - {props.updateButton && ( + {editable && (
)} - {validModel && ( -
- -
- {device.features.map(feature => ( - - -
- -
-
- ))} -
+
+ +
+ {device.features.map(feature => ( + + +
+ +
+
+ ))}
- )} +
- {validModel && props.alreadyCreatedButton && ( - )} - {validModel && props.updateButton && ( + {props.updateButton && ( )} - {validModel && props.deleteButton && ( - )} - - {!validModel && ( - - )}
diff --git a/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx b/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx index 406d6c55da..18fac2d1b9 100644 --- a/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx +++ b/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx @@ -50,9 +50,10 @@ const DeviceTab = ({ children, ...props }) => ( props.overkizDevices.map((device, index) => ( ( logger.error(error)); - logger.debug(`access_token: ${response.data.access_token}`); - - response = await axios.get( - `${this.overkizServer.configuration.COZYTOUCH_ATLANTIC_API}/gacoma/gacomawcfservice/accounts/jwt`, - { - headers: { - Authorization: `Bearer ${response.data.access_token}`, - }, - }, - ); - logger.debug(`JWT: ${response.data}`); - payload = { - jwt: response.data, - }; - } else { - payload = { - userId: overkizUsername, - userPassword: overkizUserpassword, - }; } - - const response = await axios.post(`${this.overkizServer.endpoint}/login`, new url.URLSearchParams(payload)); - - logger.info(`Overkiz : Server connection OK`); - const cookie = response.headers['set-cookie'][0]; - this.sessionCookie = cookie.substring(cookie.indexOf('=') + 1, cookie.indexOf(';')); + this.overkizServerAPI = new API({ + host: overkizServer.host, + platformLoginHandler, + polling: { + always: false, + interval: 1000, + } + }); this.connected = true; this.eventManager.emit(EVENTS.WEBSOCKET.SEND_ALL, { @@ -85,7 +66,6 @@ async function connect() { }); this.syncOverkizDevices(); - // this.updateDevicesJob = this.cron.schedule('0 */5 * * * *', this.syncOverkizDevices.bind(this)); } module.exports = { diff --git a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js index 187ee86e35..0d448a7ec3 100644 --- a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js +++ b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js @@ -1,9 +1,6 @@ -const axios = require('axios'); -const retry = require('async-retry'); const logger = require('../../../../utils/logger'); const { getDeviceFeatureExternalId, getNodeStateInfoByExternalId } = require('../utils/overkiz.externalId'); const { unbindValue } = require('../utils/overkiz.bindValue'); -const { connect } = require('./overkiz.connect'); const { EVENTS, DEVICE_FEATURE_CATEGORIES } = require('../../../../utils/constants'); /** @@ -19,41 +16,26 @@ async function getDevicesStates(device) { device.features.map(async (feature) => { const { deviceURL } = getNodeStateInfoByExternalId(feature); - const response = await retry( - async (bail) => { - const tryResponse = await axios.get( - `${this.overkizServer.endpoint}setup/devices/${encodeURIComponent(deviceURL)}/states`, - { - headers: { - 'Cache-Control': 'no-cache', - Host: this.overkizServer.endpoint.substring( - this.overkizServer.endpoint.indexOf('/') + 2, - this.overkizServer.endpoint.indexOf('/', 8), - ), - Connection: 'Keep-Alive', - Cookie: `JSESSIONID=${this.sessionCookie}`, - }, - }, - ); - return tryResponse; - }, - { - retries: 5, - onRetry: async (err, num) => { - if (err.response && err.response.status === 401) { - await connect.bind(this)(); - logger.info(`Overkiz : Connecting Overkiz server...`); - } else { - throw err; - } - }, - }, - ); + const deviceStates = await this.overkizServerAPI.get(`setup/devices/${encodeURIComponent(deviceURL)}/states`); logger.info(`Overkiz : Get new device states: ${deviceURL}`); - response.data.forEach((state) => { - const deviceFeatureExternalId = getDeviceFeatureExternalId({ deviceURL }, state.name); + deviceStates.forEach(state => { + switch(state.name) { + case 'core:ComfortRoomTemperatureState': + case 'core:EcoRoomTemperatureState': + case 'core:TargetTemperatureState': // Consigne + case 'io:EffectiveTemperatureSetpointState': + case 'io:TargetHeatingLevelState': // Mode + logger.info(`${state.name} has value ${state.value}`); + break; + default: + // + } + }); + + deviceStates.forEach((state) => { + const deviceFeatureExternalId = getDeviceFeatureExternalId({ URL: deviceURL }, state.name); const newValueUnbind = unbindValue(device, state.name, state.value); const deviceFeature = this.gladys.stateManager.get('deviceFeatureByExternalId', deviceFeatureExternalId); if (deviceFeature) { diff --git a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js index cd675a33c9..133fb4e79c 100644 --- a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js +++ b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js @@ -23,8 +23,9 @@ const { getDeviceName, getDeviceFeatureExternalId, getDeviceExternalId } = requi async function getOverkizDevices() { const deviceOids = Object.keys(this.devices); + // Search for main device (non-pod system device) const newDevices = deviceOids - .map((deviceOid) => Object.assign({}, { id: deviceOid }, this.devices[deviceOid])) + .map((deviceOid) => ({ id: deviceOid, ...this.devices[deviceOid]})) .filter((node) => node.type === DEVICE_TYPES.SYSTEM) .filter((node) => node.uiClass !== DEVICE_UID_CLASSES.POD) .map((node) => { @@ -67,36 +68,42 @@ async function getOverkizDevices() { }) .reduce((map, obj) => { // Remove # to get all nodes from the same physical device - map[obj.rawOverkizDevice.deviceURL.slice(0, -2)] = obj; + const deviceURL = obj.rawOverkizDevice.URL.includes('#') ? + obj.rawOverkizDevice.URL.substring(0, obj.rawOverkizDevice.URL.indexOf('#')) : obj.rawOverkizDevice.URL; + map[deviceURL] = obj; return map; }, {}); - // foreach node in RAM, we format it with the gladys device format + + // Search for device associated to main device (same base URL) deviceOids - .map((deviceOid) => Object.assign({}, { id: deviceOid }, this.devices[deviceOid])) - .filter((node) => newDevices[node.deviceURL.slice(0, -2)] !== undefined) + .map((deviceOid) => ({ id: deviceOid, ...this.devices[deviceOid]})) + .filter((node) => { + const deviceURL = node.URL.includes('#') ? + node.URL.substring(0, node.URL.indexOf('#')) : node.URL; + return newDevices[deviceURL] !== undefined; + }) .map((node) => { - const newDevice = newDevices[node.deviceURL.slice(0, -2)]; + const deviceURL = node.URL.includes('#') ? + node.URL.substring(0, node.URL.indexOf('#')) : node.URL; + const newDevice = newDevices[deviceURL]; const newFeature = { - rawOverkizDevice: node, + // rawOverkizDevice: node, }; if (node.uiClass === DEVICE_UID_CLASSES.HEATER) { newDevice.features.push( - Object.assign({}, newFeature, { - name: `Mode`, - selector: `overkiz-${node.deviceURL}-${node.uiClass}-${DEVICE_STATES.HEATING_LEVEL_STATE}`, + { ...newFeature, name: `Mode`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.HEATING_LEVEL_STATE}`, external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.HEATING_LEVEL_STATE), category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, type: DEVICE_FEATURE_TYPES.THERMOSTAT.MODE, read_only: false, has_feedback: true, min: 0, - max: HEATING_LEVELS.length - 1, - }), + max: HEATING_LEVELS.length - 1,}, ); newDevice.features.push( - Object.assign({}, newFeature, { - name: `Comfort mode temperature`, - selector: `overkiz-${node.deviceURL}-${node.uiClass}-${DEVICE_STATES.COMFORT_TEMPERATURE_STATE}`, + { ...newFeature, name: `Comfort mode temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.COMFORT_TEMPERATURE_STATE}`, external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.COMFORT_TEMPERATURE_STATE), category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, @@ -104,13 +111,11 @@ async function getOverkizDevices() { unit: DEVICE_FEATURE_UNITS.CELSIUS, has_feedback: true, min: 0, - max: 40, - }), + max: 40,}, ); newDevice.features.push( - Object.assign({}, newFeature, { - name: `Eco mode temperature`, - selector: `overkiz-${node.deviceURL}-${node.uiClass}-${DEVICE_STATES.ECO_TEMPERATURE_STATE}`, + { ...newFeature, name: `Eco mode temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.ECO_TEMPERATURE_STATE}`, external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.ECO_TEMPERATURE_STATE), category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, @@ -118,14 +123,12 @@ async function getOverkizDevices() { unit: DEVICE_FEATURE_UNITS.CELSIUS, has_feedback: true, min: 0, - max: 40, - }), + max: 40,}, ); } else if (node.uiClass === DEVICE_UID_CLASSES.TEMPERATURE) { newDevice.features.push( - Object.assign({}, newFeature, { - name: `Temperature`, - selector: `overkiz-${node.deviceURL}-${node.uiClass}-${DEVICE_STATES.TEMPERATURE_STATE}`, + { ...newFeature, name: `Temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.TEMPERATURE_STATE}`, external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.TEMPERATURE_STATE), category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR, type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL, @@ -133,14 +136,12 @@ async function getOverkizDevices() { unit: DEVICE_FEATURE_UNITS.CELSIUS, has_feedback: true, min: 0, - max: 40, - }), + max: 40,}, ); } else if (node.uiClass === DEVICE_UID_CLASSES.OCCUPANCY) { newDevice.features.push( - Object.assign({}, newFeature, { - name: `Occupancy`, - selector: `overkiz-${node.deviceURL}-${node.uiClass}-${DEVICE_STATES.OCCUPANCY_STATE}`, + { ...newFeature, name: `Occupancy`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.OCCUPANCY_STATE}`, external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.OCCUPANCY_STATE), category: DEVICE_FEATURE_CATEGORIES.PRESENCE_SENSOR, type: DEVICE_FEATURE_TYPES.SENSOR.PUSH, @@ -148,8 +149,7 @@ async function getOverkizDevices() { max: 1, read_only: true, has_feedback: false, - keep_history: true, - }), + keep_history: true,}, ); } @@ -158,8 +158,8 @@ async function getOverkizDevices() { const newDevicesOids = Object.keys(newDevices); return newDevicesOids - .map((newDevicesOid) => Object.assign({}, newDevices[newDevicesOid])) - .sort(function sortByNodeReady(a, b) { + .map((newDevicesOid) => ({ ...newDevices[newDevicesOid]})) + .sort((a, b) => { return b.ready - a.ready || a.rawOverkizDevice.id - b.rawOverkizDevice.id; }); } diff --git a/server/services/overkiz/lib/commands/overkiz.sendCommand.js b/server/services/overkiz/lib/commands/overkiz.sendCommand.js index 9ad7216fbd..e3fa2bea6c 100644 --- a/server/services/overkiz/lib/commands/overkiz.sendCommand.js +++ b/server/services/overkiz/lib/commands/overkiz.sendCommand.js @@ -7,15 +7,14 @@ const { connect } = require('./overkiz.connect'); /** * @description Connect to OverKiz server. - * @param {string} execId - Execution Id. * @returns {Promise} Return state of Execution. * @example - * overkiz.getExecutionState('01234'); + * overkiz.getExecutionStates(); */ -async function getExecutionState(execId) { +async function getExecutionStates() { const response = await retry( async (bail) => { - const tryResponse = await axios.get(`${this.overkizServer.endpoint}exec/current/${execId}`, { + const tryResponse = await axios.get(`${this.overkizServer.endpoint}exec/current`, { headers: { 'Cache-Control': 'no-cache', Host: this.overkizServer.endpoint.substring( @@ -46,33 +45,15 @@ async function getExecutionState(execId) { /** * @description Connect to OverKiz server. - * @param {Object} command - Command to send. - * @param {string} deviceURL - DeviceURL. - * @param {Object} data - Command data to send. - * @returns {Promise} Return Object of informations. + * @param {string} execId - Execution Id. + * @returns {Promise} Return state of Execution. * @example - * overkiz.sendCommand(); + * overkiz.getExecutionState('01234'); */ -async function sendCommand(command, deviceURL, data) { - logger.info(`Overkiz : Sending command...`); - - const payload = { - label: `${command} to device ${deviceURL}`, - actions: [ - { - deviceURL, - commands: [ - { - name: command, - parameters: [data], - }, - ], - }, - ], - }; +async function getExecutionState(execId) { const response = await retry( async (bail) => { - const tryResponse = await axios.post(`${this.overkizServer.endpoint}exec/apply`, payload, { + const tryResponse = await axios.get(`${this.overkizServer.endpoint}exec/current/${execId}`, { headers: { 'Cache-Control': 'no-cache', Host: this.overkizServer.endpoint.substring( @@ -98,30 +79,39 @@ async function sendCommand(command, deviceURL, data) { }, ); - logger.info(`Overkiz : Command sent - Exec Id: ${response.data.execId}`); - - const { execId } = response.data; - - let execResponse = await getExecutionState.bind(this)(execId); - const { state1 } = execResponse.data; - logger.debug(state1); - await sleep(500); // Wait 2000 ms + return response; +} - execResponse = await getExecutionState.bind(this)(execId); - const { state2 } = execResponse.data; - logger.debug(state2); - await sleep(500); // Wait 2000 ms +/** + * @description Connect to OverKiz server. + * @param {Object} command - Command to send. + * @param {string} deviceURL - DeviceURL. + * @param {Object} data - Command data to send. + * @returns {Promise} Return Object of informations. + * @example + * overkiz.sendCommand(); + */ +async function sendCommand(command, deviceURL, data) { + logger.info(`Overkiz : Sending command...`); - execResponse = await getExecutionState.bind(this)(execId); - const { state3 } = execResponse.data; - logger.debug(state3); - await sleep(500); // Wait 2000 ms + const payload = { + label: `${command} to device ${deviceURL}`, + actions: [ + { + deviceURL, + commands: [ + { + name: command, + parameters: [data], + }, + ], + }, + ], + }; - execResponse = await getExecutionState.bind(this)(execId); - const { state4 } = execResponse.data; - await sleep(500); // Wait 2000 ms - - logger.debug(state4); + const response = await this.overkizServerAPI.exec(payload); + const status = await response.wait(); + logger.debug(`Command sent: ${response.execId} - ${status}`); } module.exports = { diff --git a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js index d5b307b0f5..0370d0e9b6 100644 --- a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js +++ b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js @@ -1,12 +1,42 @@ -const axios = require('axios'); -const retry = require('async-retry'); const logger = require('../../../../utils/logger'); -const { updateGatewayState } = require('../overkiz.util'); -const { updateDevicesState } = require('../overkiz.util'); -const { connect } = require('./overkiz.connect'); const { ServiceNotConfiguredError } = require('../../../../utils/coreErrors'); +/** + * @description Update Gateway State. + * @param {Object} gateways - List of gateways. + * @example + * overkiz.updateGatewayState(); + */ +function updateGatewayState(gateways) { + logger.debug('UpdateGatwayState'); + + this.gateways = gateways; + + // TODO send event +} + +/** + * @description Update Devices State. + * @param {Object} devices - Devices. + * @param {Object} rootPlace - RootPlace. + * @return {Object} + * @example + * overkiz.updateDevicesState(devices, rootPlace); + */ +function updateDevicesState(devices, rootPlace) { + logger.debug('UpdateDevicesState'); + + devices.forEach((device) => { + const placeObj = rootPlace.subPlaces.find((place) => place.oid === device.placeOID); + if (placeObj) { + device.place = placeObj.name; + } + this.devices[device.oid] = device; + delete this.devices[device.oid].api; + }); +} + /** * @description Synchronize Overkiz devices. * @returns {Promise} Overkiz devices. @@ -18,39 +48,14 @@ async function syncOverkizDevices() { throw new ServiceNotConfiguredError('OVERKIZ_NOT_CONNECTED'); } logger.debug(`Overkiz : Starting discovery`); + this.scanInProgress = true; - const response = await retry( - async (bail) => { - const tryResponse = await axios.get(`${this.overkizServer.endpoint}setup`, { - headers: { - 'Cache-Control': 'no-cache', - Host: this.overkizServer.endpoint.substring( - this.overkizServer.endpoint.indexOf('/') + 2, - this.overkizServer.endpoint.indexOf('/', 8), - ), - Connection: 'Keep-Alive', - Cookie: `JSESSIONID=${this.sessionCookie}`, - }, - }); - return tryResponse; - }, - { - retries: 5, - onRetry: async (err, num) => { - if (err.response && err.response.status === 401) { - await connect.bind(this)(); - logger.info(`Overkiz : Connecting Overkiz server...`); - } else { - throw err; - } - }, - }, - ); - - updateGatewayState.bind(this)(response.data.gateways); - - updateDevicesState.bind(this)(response.data.devices, response.data.rootPlace); + const setup = await this.overkizServerAPI.getSetup(); + updateGatewayState.call(this, setup.gateways[0]); + + const devices = await this.overkizServerAPI.getObjects(); + updateDevicesState.call(this, devices, setup.rootPlace); this.scanInProgress = false; } diff --git a/server/services/overkiz/lib/overkiz.util.js b/server/services/overkiz/lib/overkiz.util.js deleted file mode 100644 index 6119b29463..0000000000 --- a/server/services/overkiz/lib/overkiz.util.js +++ /dev/null @@ -1,39 +0,0 @@ -const logger = require('../../../utils/logger'); - -/** - * @description Update Gateway State. - * @param {Object} gateways - List of gateways. - * @example - * overkiz.updateGatewayState(); - */ -function updateGatewayState(gateways) { - logger.debug('UpdateGatwayState'); - - this.gateways = gateways; - - // TODO send event -} - -/** - * @description Update Devices State. - * @param {Object} devices - Devices. - * @param {Object} rootPlace - RootPlace. - * @example - * overkiz.updateDevicesState(devices, rootPlace); - */ -function updateDevicesState(devices, rootPlace) { - logger.debug('UpdateDevicesState'); - - devices.forEach((device) => { - const placeObj = rootPlace.subPlaces.find((place) => place.oid === device.placeOID); - if (placeObj) { - device.place = placeObj.label; - } - this.devices[device.oid] = device; - }); -} - -module.exports = { - updateGatewayState, - updateDevicesState, -}; diff --git a/server/services/overkiz/lib/utils/overkiz.constants.js b/server/services/overkiz/lib/utils/overkiz.constants.js index fb19826ca8..7f8ccbec82 100644 --- a/server/services/overkiz/lib/utils/overkiz.constants.js +++ b/server/services/overkiz/lib/utils/overkiz.constants.js @@ -4,6 +4,7 @@ const DEVICE_ONLINE = 'ONLINE'; const SUPPORTED_SERVERS = { atlantic_cozytouch: { name: 'Atlantic Cozytouch', + host: 'ha110-1.overkiz.com', endpoint: 'https://ha110-1.overkiz.com/enduser-mobile-web/enduserAPI/', manufacturer: 'Atlantic', jwt: true, @@ -15,24 +16,28 @@ const SUPPORTED_SERVERS = { }, hi_kumo_asia: { name: 'Hitachi Hi Kumo (Asia)', + host: 'ha203-1.overkiz.com', endpoint: 'https://ha203-1.overkiz.com/enduser-mobile-web/enduserAPI/', manufacturer: 'Hitachi', configuration_url: undefined, }, hi_kumo_europe: { name: 'Hitachi Hi Kumo (Europe)', + host: 'ha117-1.overkiz.com', endpoint: 'https://ha117-1.overkiz.com/enduser-mobile-web/enduserAPI/', manufacturer: 'Hitachi', configuration_url: undefined, }, hi_kumo_oceania: { name: 'Hitachi Hi Kumo (Oceania)', + host: 'ha203-1.overkiz.com', endpoint: 'https://ha203-1.overkiz.com/enduser-mobile-web/enduserAPI/', manufacturer: 'Hitachi', configuration_url: undefined, }, nexity: { name: 'Nexity Eugénie', + host: 'ha106-1.overkiz.com', endpoint: 'https://ha106-1.overkiz.com/enduser-mobile-web/enduserAPI/', manufacturer: 'Nexity', configuration: { @@ -69,6 +74,7 @@ const SUPPORTED_SERVERS = { configuration_url: undefined, }, }; + const OVERKIZ_API = { GET_DEVICES: 'setup/devices', GET_GATEWAYS: 'setup/gateways', diff --git a/server/services/overkiz/lib/utils/overkiz.externalId.js b/server/services/overkiz/lib/utils/overkiz.externalId.js index b6d5471704..e2209415e7 100644 --- a/server/services/overkiz/lib/utils/overkiz.externalId.js +++ b/server/services/overkiz/lib/utils/overkiz.externalId.js @@ -6,7 +6,7 @@ * getDeviceName(node); */ function getDeviceName(node) { - return `${node.label} (${node.place})`; + return `${node.name} (${node.place})`; } /** @@ -17,7 +17,8 @@ function getDeviceName(node) { * getDeviceExternalId(node); */ function getDeviceExternalId(node) { - return `overkiz:deviceURL:${node.deviceURL}`; + const deviceURL = node.URL; + return `overkiz:deviceURL:${deviceURL}`; } /** @@ -29,7 +30,8 @@ function getDeviceExternalId(node) { * getDeviceFeatureExternalId(node); */ function getDeviceFeatureExternalId(node, state) { - return `overkiz:deviceURL:${node.deviceURL}:state:${state}`; + const deviceURL = node.URL; + return `overkiz:deviceURL:${deviceURL}:state:${state}`; } /** diff --git a/server/services/overkiz/package-lock.json b/server/services/overkiz/package-lock.json index 588d17480d..f4cf2c92d6 100644 --- a/server/services/overkiz/package-lock.json +++ b/server/services/overkiz/package-lock.json @@ -1,16 +1,612 @@ { "name": "gladys-overkiz", + "lockfileVersion": 2, "requires": true, - "lockfileVersion": 1, + "packages": { + "": { + "name": "gladys-overkiz", + "cpu": [ + "x64", + "arm", + "arm64" + ], + "os": [ + "darwin", + "linux", + "win32" + ], + "dependencies": { + "axios": "^0.21.1", + "bluebird": "^3.7.0", + "bottleneck": "^2.19.5", + "node-cron": "^3.0.2", + "overkiz-api": "^2.0.1", + "sleep-promise": "^9.1.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/follow-redirects": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", + "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-cron": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz", + "integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==", + "dependencies": { + "uuid": "8.3.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/overkiz-api": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/overkiz-api/-/overkiz-api-2.0.1.tgz", + "integrity": "sha512-rMrHFO+dMY0/6XW6QoAYn9U2jDR54nQ7Oq/0SFu6JioU4aug5xkYcDb6itrKfzoD8elecaSidq1XMbQC3oIBVw==", + "dependencies": { + "request": "^2.88.2", + "request-promise": "^4.2.6" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", + "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", + "deprecated": "request-promise has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", + "dependencies": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dependencies": { + "lodash": "^4.17.19" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sleep-promise": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/sleep-promise/-/sleep-promise-9.1.0.tgz", + "integrity": "sha512-UHYzVpz9Xn8b+jikYSD6bqvf754xL2uBUzDFwiU6NcdZeifPr6UfgU43xpkPu67VMS88+TI2PSI7Eohgqf2fKA==" + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + } + }, "dependencies": { - "async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "requires": { - "retry": "0.13.1" + "safer-buffer": "~2.1.0" } }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, "axios": { "version": "0.21.4", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", @@ -19,6 +615,14 @@ "follow-redirects": "^1.14.0" } }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "requires": { + "tweetnacl": "^0.14.3" + } + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -29,11 +633,177 @@ "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, "follow-redirects": { "version": "1.14.5", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, "node-cron": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz", @@ -42,20 +812,173 @@ "uuid": "8.3.2" } }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "overkiz-api": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/overkiz-api/-/overkiz-api-2.0.1.tgz", + "integrity": "sha512-rMrHFO+dMY0/6XW6QoAYn9U2jDR54nQ7Oq/0SFu6JioU4aug5xkYcDb6itrKfzoD8elecaSidq1XMbQC3oIBVw==", + "requires": { + "request": "^2.88.2", + "request-promise": "^4.2.6" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "request-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", + "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", + "requires": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "requires": { + "lodash": "^4.17.19" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sleep-promise": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/sleep-promise/-/sleep-promise-9.1.0.tgz", "integrity": "sha512-UHYzVpz9Xn8b+jikYSD6bqvf754xL2uBUzDFwiU6NcdZeifPr6UfgU43xpkPu67VMS88+TI2PSI7Eohgqf2fKA==" }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } } } } diff --git a/server/services/overkiz/package.json b/server/services/overkiz/package.json index 0b564c5f54..5dcef738ce 100644 --- a/server/services/overkiz/package.json +++ b/server/services/overkiz/package.json @@ -13,11 +13,11 @@ ], "scripts": {}, "dependencies": { - "async-retry": "^1.3.3", "axios": "^0.21.1", "bluebird": "^3.7.0", "bottleneck": "^2.19.5", "node-cron": "^3.0.2", + "overkiz-api": "^2.0.1", "sleep-promise": "^9.1.0" } } From e60bc998cf0767ef8dc963cad8765a535142b507 Mon Sep 17 00:00:00 2001 From: POCHET Romuald Date: Sat, 1 Apr 2023 15:51:56 +0200 Subject: [PATCH 06/40] Merge --- .../ThermostatModeDeviceFeature.jsx | 30 +++++++++++++------ front/src/config/i18n/fr.json | 2 +- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx b/front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx index 714da81200..fa706e1127 100644 --- a/front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx +++ b/front/src/components/boxs/device-in-room/device-features/ThermostatModeDeviceFeature.jsx @@ -38,19 +38,31 @@ const ThermostatModeDeviceType = ({ children, ...props }) => { {getDeviceName(props.device, props.deviceFeature)} - - - diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index eb8427b7f4..b37db57d07 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -1067,7 +1067,7 @@ "roomLabel": "Pièce", "createButton": "Sauvegarder", "updateButton": "Mettre à jour", - "deleteButton": "Supprimer", + "deleteButton": "Supprimer", "featuresLabel": "", "editButton": "" }, From c69bcbd0311b1c314fb64a2a0ebf5cc3e3ffdcc3 Mon Sep 17 00:00:00 2001 From: POCHET Romuald Date: Sat, 1 Apr 2023 18:24:18 +0200 Subject: [PATCH 07/40] ESLint --- .../routes/integration/all/overkiz/actions.js | 2 +- .../all/overkiz/discover-page/EmptyState.jsx | 2 +- .../overkiz/lib/commands/overkiz.connect.js | 15 +- .../lib/commands/overkiz.disconnect.js | 2 +- .../lib/commands/overkiz.getDevicesStates.js | 17 +-- .../lib/commands/overkiz.getOverkizDevices.js | 144 +++++++++--------- .../lib/commands/overkiz.sendCommand.js | 13 +- .../commands/overkiz.syncOverkizDevices.js | 9 +- server/services/overkiz/package-lock.json | 30 ++++ server/services/overkiz/package.json | 4 +- 10 files changed, 129 insertions(+), 109 deletions(-) diff --git a/front/src/routes/integration/all/overkiz/actions.js b/front/src/routes/integration/all/overkiz/actions.js index fff3efb63e..7765e2ea76 100644 --- a/front/src/routes/integration/all/overkiz/actions.js +++ b/front/src/routes/integration/all/overkiz/actions.js @@ -62,7 +62,7 @@ function createActions(store) { }); } }, - displayConnectedMessage(state) { + displayConnectedMessage() { // display 3 seconds a message "Overkiz connected" store.setState({ overkizConnected: true, diff --git a/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx b/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx index 25b7a257aa..d78ff0b8c7 100644 --- a/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx +++ b/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx @@ -2,7 +2,7 @@ import { MarkupText } from 'preact-i18n'; import cx from 'classnames'; import style from './style.css'; -const EmptyState = ({ children }) => ( +const EmptyState = ({ }) => (
diff --git a/server/services/overkiz/lib/commands/overkiz.connect.js b/server/services/overkiz/lib/commands/overkiz.connect.js index f479a02063..7ae220ed23 100644 --- a/server/services/overkiz/lib/commands/overkiz.connect.js +++ b/server/services/overkiz/lib/commands/overkiz.connect.js @@ -36,19 +36,12 @@ async function connect() { const overkizServer = SUPPORTED_SERVERS[overkizType]; let platformLoginHandler; - switch(overkizType) { + switch (overkizType) { case 'atlantic_cozytouch': - platformLoginHandler = new CozytouchLoginHandler( - overkizUsername, - overkizUserpassword, - ); + platformLoginHandler = new CozytouchLoginHandler(overkizUsername, overkizUserpassword); break; default: - platformLoginHandler = new DefaultLoginHandler( - overkizUsername, - overkizUserpassword, - ); - + platformLoginHandler = new DefaultLoginHandler(overkizUsername, overkizUserpassword); } this.overkizServerAPI = new API({ host: overkizServer.host, @@ -56,7 +49,7 @@ async function connect() { polling: { always: false, interval: 1000, - } + }, }); this.connected = true; diff --git a/server/services/overkiz/lib/commands/overkiz.disconnect.js b/server/services/overkiz/lib/commands/overkiz.disconnect.js index 6692520aa0..f9c2c7b050 100644 --- a/server/services/overkiz/lib/commands/overkiz.disconnect.js +++ b/server/services/overkiz/lib/commands/overkiz.disconnect.js @@ -9,7 +9,7 @@ const logger = require('../../../../utils/logger'); async function disconnect() { logger.info(`Overkiz : Disonnecting Overkiz...`); - if(this.updateDevicesJob) { + if (this.updateDevicesJob) { this.updateDevicesJob.stop(); } } diff --git a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js index 0d448a7ec3..9475e10067 100644 --- a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js +++ b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js @@ -20,8 +20,8 @@ async function getDevicesStates(device) { logger.info(`Overkiz : Get new device states: ${deviceURL}`); - deviceStates.forEach(state => { - switch(state.name) { + deviceStates.forEach((state) => { + switch (state.name) { case 'core:ComfortRoomTemperatureState': case 'core:EcoRoomTemperatureState': case 'core:TargetTemperatureState': // Consigne @@ -30,7 +30,7 @@ async function getDevicesStates(device) { logger.info(`${state.name} has value ${state.value}`); break; default: - // + // } }); @@ -39,12 +39,11 @@ async function getDevicesStates(device) { const newValueUnbind = unbindValue(device, state.name, state.value); const deviceFeature = this.gladys.stateManager.get('deviceFeatureByExternalId', deviceFeatureExternalId); if (deviceFeature) { - if(deviceFeature.category !== DEVICE_FEATURE_CATEGORIES.PRESENCE_SENSOR || - newValueUnbind !== 0) { - this.eventManager.emit(EVENTS.DEVICE.NEW_STATE, { - device_feature_external_id: deviceFeatureExternalId, - state: newValueUnbind, - }); + if (deviceFeature.category !== DEVICE_FEATURE_CATEGORIES.PRESENCE_SENSOR || newValueUnbind !== 0) { + this.eventManager.emit(EVENTS.DEVICE.NEW_STATE, { + device_feature_external_id: deviceFeatureExternalId, + state: newValueUnbind, + }); } } }); diff --git a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js index 133fb4e79c..0678f266f8 100644 --- a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js +++ b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js @@ -25,7 +25,7 @@ async function getOverkizDevices() { // Search for main device (non-pod system device) const newDevices = deviceOids - .map((deviceOid) => ({ id: deviceOid, ...this.devices[deviceOid]})) + .map((deviceOid) => ({ id: deviceOid, ...this.devices[deviceOid] })) .filter((node) => node.type === DEVICE_TYPES.SYSTEM) .filter((node) => node.uiClass !== DEVICE_UID_CLASSES.POD) .map((node) => { @@ -68,97 +68,101 @@ async function getOverkizDevices() { }) .reduce((map, obj) => { // Remove # to get all nodes from the same physical device - const deviceURL = obj.rawOverkizDevice.URL.includes('#') ? - obj.rawOverkizDevice.URL.substring(0, obj.rawOverkizDevice.URL.indexOf('#')) : obj.rawOverkizDevice.URL; + const deviceURL = obj.rawOverkizDevice.URL.includes('#') + ? obj.rawOverkizDevice.URL.substring(0, obj.rawOverkizDevice.URL.indexOf('#')) + : obj.rawOverkizDevice.URL; map[deviceURL] = obj; return map; }, {}); - + // Search for device associated to main device (same base URL) deviceOids - .map((deviceOid) => ({ id: deviceOid, ...this.devices[deviceOid]})) + .map((deviceOid) => ({ id: deviceOid, ...this.devices[deviceOid] })) .filter((node) => { - const deviceURL = node.URL.includes('#') ? - node.URL.substring(0, node.URL.indexOf('#')) : node.URL; + const deviceURL = node.URL.includes('#') ? node.URL.substring(0, node.URL.indexOf('#')) : node.URL; return newDevices[deviceURL] !== undefined; }) .map((node) => { - const deviceURL = node.URL.includes('#') ? - node.URL.substring(0, node.URL.indexOf('#')) : node.URL; + const deviceURL = node.URL.includes('#') ? node.URL.substring(0, node.URL.indexOf('#')) : node.URL; const newDevice = newDevices[deviceURL]; const newFeature = { // rawOverkizDevice: node, }; if (node.uiClass === DEVICE_UID_CLASSES.HEATER) { - newDevice.features.push( - { ...newFeature, name: `Mode`, - selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.HEATING_LEVEL_STATE}`, - external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.HEATING_LEVEL_STATE), - category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, - type: DEVICE_FEATURE_TYPES.THERMOSTAT.MODE, - read_only: false, - has_feedback: true, - min: 0, - max: HEATING_LEVELS.length - 1,}, - ); - newDevice.features.push( - { ...newFeature, name: `Comfort mode temperature`, - selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.COMFORT_TEMPERATURE_STATE}`, - external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.COMFORT_TEMPERATURE_STATE), - category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, - type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, - read_only: false, - unit: DEVICE_FEATURE_UNITS.CELSIUS, - has_feedback: true, - min: 0, - max: 40,}, - ); - newDevice.features.push( - { ...newFeature, name: `Eco mode temperature`, - selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.ECO_TEMPERATURE_STATE}`, - external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.ECO_TEMPERATURE_STATE), - category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, - type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, - read_only: false, - unit: DEVICE_FEATURE_UNITS.CELSIUS, - has_feedback: true, - min: 0, - max: 40,}, - ); + newDevice.features.push({ + ...newFeature, + name: `Mode`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.HEATING_LEVEL_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.HEATING_LEVEL_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.MODE, + read_only: false, + has_feedback: true, + min: 0, + max: HEATING_LEVELS.length - 1, + }); + newDevice.features.push({ + ...newFeature, + name: `Comfort mode temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.COMFORT_TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.COMFORT_TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, + read_only: false, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }); + newDevice.features.push({ + ...newFeature, + name: `Eco mode temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.ECO_TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.ECO_TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, + read_only: false, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }); } else if (node.uiClass === DEVICE_UID_CLASSES.TEMPERATURE) { - newDevice.features.push( - { ...newFeature, name: `Temperature`, - selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.TEMPERATURE_STATE}`, - external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.TEMPERATURE_STATE), - category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR, - type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL, - read_only: true, - unit: DEVICE_FEATURE_UNITS.CELSIUS, - has_feedback: true, - min: 0, - max: 40,}, - ); + newDevice.features.push({ + ...newFeature, + name: `Temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR, + type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL, + read_only: true, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }); } else if (node.uiClass === DEVICE_UID_CLASSES.OCCUPANCY) { - newDevice.features.push( - { ...newFeature, name: `Occupancy`, - selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.OCCUPANCY_STATE}`, - external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.OCCUPANCY_STATE), - category: DEVICE_FEATURE_CATEGORIES.PRESENCE_SENSOR, - type: DEVICE_FEATURE_TYPES.SENSOR.PUSH, - min: 0, - max: 1, - read_only: true, - has_feedback: false, - keep_history: true,}, - ); + newDevice.features.push({ + ...newFeature, + name: `Occupancy`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.OCCUPANCY_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.OCCUPANCY_STATE), + category: DEVICE_FEATURE_CATEGORIES.PRESENCE_SENSOR, + type: DEVICE_FEATURE_TYPES.SENSOR.PUSH, + min: 0, + max: 1, + read_only: true, + has_feedback: false, + keep_history: true, + }); } - + return newDevice; }); const newDevicesOids = Object.keys(newDevices); return newDevicesOids - .map((newDevicesOid) => ({ ...newDevices[newDevicesOid]})) + .map((newDevicesOid) => ({ ...newDevices[newDevicesOid] })) .sort((a, b) => { return b.ready - a.ready || a.rawOverkizDevice.id - b.rawOverkizDevice.id; }); diff --git a/server/services/overkiz/lib/commands/overkiz.sendCommand.js b/server/services/overkiz/lib/commands/overkiz.sendCommand.js index e3fa2bea6c..24d1404044 100644 --- a/server/services/overkiz/lib/commands/overkiz.sendCommand.js +++ b/server/services/overkiz/lib/commands/overkiz.sendCommand.js @@ -1,17 +1,12 @@ -const axios = require('axios'); -const retry = require('async-retry'); -const sleep = require('sleep-promise'); const logger = require('../../../../utils/logger'); -const { connect } = require('./overkiz.connect'); - /** * @description Connect to OverKiz server. * @returns {Promise} Return state of Execution. * @example * overkiz.getExecutionStates(); */ -async function getExecutionStates() { +/* async function getExecutionStates() { const response = await retry( async (bail) => { const tryResponse = await axios.get(`${this.overkizServer.endpoint}exec/current`, { @@ -41,7 +36,7 @@ async function getExecutionStates() { ); return response; -} +} */ /** * @description Connect to OverKiz server. @@ -50,7 +45,7 @@ async function getExecutionStates() { * @example * overkiz.getExecutionState('01234'); */ -async function getExecutionState(execId) { +/* async function getExecutionState(execId) { const response = await retry( async (bail) => { const tryResponse = await axios.get(`${this.overkizServer.endpoint}exec/current/${execId}`, { @@ -80,7 +75,7 @@ async function getExecutionState(execId) { ); return response; -} +} */ /** * @description Connect to OverKiz server. diff --git a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js index 0370d0e9b6..7d09c0abca 100644 --- a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js +++ b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js @@ -12,15 +12,13 @@ function updateGatewayState(gateways) { logger.debug('UpdateGatwayState'); this.gateways = gateways; - - // TODO send event } +// eslint-disable-next-line jsdoc/require-returns /** * @description Update Devices State. - * @param {Object} devices - Devices. - * @param {Object} rootPlace - RootPlace. - * @return {Object} + * @param {Object} devices - List of devices. + * @param {Object} rootPlace - Root place. * @example * overkiz.updateDevicesState(devices, rootPlace); */ @@ -62,4 +60,5 @@ async function syncOverkizDevices() { module.exports = { syncOverkizDevices, + updateDevicesState, }; diff --git a/server/services/overkiz/package-lock.json b/server/services/overkiz/package-lock.json index f4cf2c92d6..37468d4976 100644 --- a/server/services/overkiz/package-lock.json +++ b/server/services/overkiz/package-lock.json @@ -16,6 +16,7 @@ "win32" ], "dependencies": { + "async-retry": "^1.3.3", "axios": "^0.21.1", "bluebird": "^3.7.0", "bottleneck": "^2.19.5", @@ -55,6 +56,14 @@ "node": ">=0.8" } }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dependencies": { + "retry": "0.13.1" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -448,6 +457,14 @@ "uuid": "bin/uuid" } }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -592,6 +609,14 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" }, + "async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "requires": { + "retry": "0.13.1" + } + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -899,6 +924,11 @@ "lodash": "^4.17.19" } }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", diff --git a/server/services/overkiz/package.json b/server/services/overkiz/package.json index 5dcef738ce..e98835d952 100644 --- a/server/services/overkiz/package.json +++ b/server/services/overkiz/package.json @@ -13,11 +13,11 @@ ], "scripts": {}, "dependencies": { + "async-retry": "^1.3.3", "axios": "^0.21.1", "bluebird": "^3.7.0", "bottleneck": "^2.19.5", "node-cron": "^3.0.2", - "overkiz-api": "^2.0.1", - "sleep-promise": "^9.1.0" + "overkiz-api": "^2.0.1" } } From b13214c79a038e4dae010a6656147ccfcc0d66d9 Mon Sep 17 00:00:00 2001 From: POCHET Romuald Date: Sat, 1 Apr 2023 19:00:28 +0200 Subject: [PATCH 08/40] Documentation link --- front/src/config/i18n/en.json | 1 + front/src/config/i18n/fr.json | 1 + .../routes/integration/all/overkiz/OverkizPage.jsx | 14 +++++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index d4f1a8651a..d748a8b7a3 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -1057,6 +1057,7 @@ "discoverTab": "", "discoverDeviceDescr": "", "setupTab": "", + "documentation": "Overkiz documentation", "device": { "title": "", "search": "", diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index b37db57d07..d67e1c2bcc 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -1057,6 +1057,7 @@ "discoverTab": "Découverte", "discoverDeviceDescr": "", "setupTab": "Configuration", + "documentation": "Documentation Overkiz", "device": { "title": "", "search": "", diff --git a/front/src/routes/integration/all/overkiz/OverkizPage.jsx b/front/src/routes/integration/all/overkiz/OverkizPage.jsx index ec7ba95f94..c5a934f67c 100644 --- a/front/src/routes/integration/all/overkiz/OverkizPage.jsx +++ b/front/src/routes/integration/all/overkiz/OverkizPage.jsx @@ -1,7 +1,8 @@ import { Text } from 'preact-i18n'; import { Link } from 'preact-router/match'; +import DeviceConfigurationLink from '../../../../components/documentation/DeviceConfigurationLink'; -const OverkizPage = ({ children }) => ( +const OverkizPage = ({ children, user }) => (
@@ -45,6 +46,17 @@ const OverkizPage = ({ children }) => ( + + + + + + +
From 2f005f3b012b942d760658a782f5fd189215a39e Mon Sep 17 00:00:00 2001 From: POCHET Romuald Date: Wed, 5 Apr 2023 23:52:25 +0200 Subject: [PATCH 09/40] sync --- front/src/components/app.jsx | 4 +- front/src/config/i18n/en.json | 17 ++- front/src/config/i18n/fr.json | 15 +- .../all/ewelink/EweLinkDeviceBox.jsx | 4 +- .../all/overkiz/OverkizDeviceBox.jsx | 8 +- .../integration/all/overkiz/OverkizPage.jsx | 4 +- .../routes/integration/all/overkiz/actions.js | 81 ++++++----- .../all/overkiz/discover-page/DiscoverTab.jsx | 4 +- .../all/overkiz/settings-page/SettingsTab.jsx | 136 ++++++++++++++++++ .../{setup-page => settings-page}/index.js | 16 ++- .../all/overkiz/setup-page/SetupTab.jsx | 93 ------------ server/lib/device/device.setupPoll.js | 2 +- server/services/index.js | 2 +- .../overkiz/api/overkiz.controller.js | 51 +++++-- .../overkiz/lib/commands/overkiz.config.js | 34 ----- .../lib/commands/overkiz.configuration.js | 56 ++++++++ .../lib/commands/overkiz.getOverkizDevices.js | 107 ++++++++------ server/services/overkiz/lib/index.js | 23 ++- .../overkiz/lib/utils/overkiz.bindValue.js | 6 +- .../overkiz/lib/utils/overkiz.constants.js | 26 +++- 20 files changed, 421 insertions(+), 268 deletions(-) create mode 100644 front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx rename front/src/routes/integration/all/overkiz/{setup-page => settings-page}/index.js (65%) delete mode 100644 front/src/routes/integration/all/overkiz/setup-page/SetupTab.jsx delete mode 100644 server/services/overkiz/lib/commands/overkiz.config.js create mode 100644 server/services/overkiz/lib/commands/overkiz.configuration.js diff --git a/front/src/components/app.jsx b/front/src/components/app.jsx index 64a719d4a7..1c3832a3de 100644 --- a/front/src/components/app.jsx +++ b/front/src/components/app.jsx @@ -123,7 +123,7 @@ import EweLinkSetupPage from '../routes/integration/all/ewelink/setup-page'; import OverkizPage from '../routes/integration/all/overkiz/device-page'; import OverkizEditPage from '../routes/integration/all/overkiz/edit-page'; import OverkizDiscoverPage from '../routes/integration/all/overkiz/discover-page'; -import OverkizSetupPage from '../routes/integration/all/overkiz/setup-page'; +import OverkizSetupPage from '../routes/integration/all/overkiz/settings-page'; const defaultState = getDefaultState(); const store = createStore(defaultState); @@ -240,7 +240,7 @@ const AppRouter = connect( - + diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index d748a8b7a3..264813c741 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -1053,10 +1053,10 @@ "overkiz": { "title": "Overkiz", "description": "Control your Overkiz devices.", - "deviceTab": "", - "discoverTab": "", + "deviceTab": "Devices", + "discoverTab": "Overkiz discover", "discoverDeviceDescr": "", - "setupTab": "", + "settingsTab": "Configuration", "documentation": "Overkiz documentation", "device": { "title": "", @@ -1082,18 +1082,25 @@ "description": "", "noDeviceFound": "No Overkiz device found." }, - "setup": { + "settings": { "title": "Overkiz configuration", "overkizDescription": "You can connect Gladys to your Overkiz cloud account to command the associated devices.", + "typeLabel": "Type", + "typePlaceholder": "Enter Overkiz type", "userLabel": "Username", "userPlaceholder": "Enter Overkiz username", "passwordLabel": "Password", "passwordPlaceholder": "Enter Overkiz password", - "saveLabel": "Save configuration", + "connectButton": "Connection", "error": "An error occured while saving configuration.", "connecting": "Configuration saved. Now connecting to your Overkiz cloud account...", "connected": "Connected to the Overkiz cloud account with success !", "connectionError": "Error while connecting, please check your configuration." + }, + "error": { + "defaultError": "There was an error saving the device.", + "defaultDeletionError": "There was an error deleting the device.", + "conflictError": "Current device is already in Gladys." } } }, diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index d67e1c2bcc..0bf4fa6f32 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -1054,9 +1054,9 @@ "title": "Overkiz", "description": "Contrôler vos appareils Overkiz.", "deviceTab": "Appareils", - "discoverTab": "Découverte", + "discoverTab": "Découverte Overkiz", "discoverDeviceDescr": "", - "setupTab": "Configuration", + "settingsTab": "Configuration", "documentation": "Documentation Overkiz", "device": { "title": "", @@ -1082,18 +1082,25 @@ "description": "Les appareils Overkiz sont automatiquement découverts. Vos appareils Overkiz doivent être ajoutés à votre compte cloud Overkiz avant.", "noDeviceFound": "Aucun périphérique Overkiz détecté." }, - "setup": { + "settings": { "title": "Configuration Overkiz", "overkizDescription": "Vous pouvez connecter Gladys à votre compte cloud Overkiz pour commander les appareils associés.", "error": "Une erreur s'est produite lors de la sauvegarde de la configuration.", "connecting": "Configuration sauvegardée. Connexion à votre compte cloud Overkiz...", "connected": "Connexion réussie au compte cloud Overkiz !", "connectionError": "Erreur lors de la connexion, veuillez vérifier votre configuration.", + "typeLabel": "Type", + "typePlaceholder": "Entrez le type Overkiz", "userLabel": "Nom d'utilisateur", "userPlaceholder": "Entrez le nom d'utilisateur Overkiz", "passwordLabel": "Mot de passe", "passwordPlaceholder": "Entrez le mot de passe utilisateur Overkiz", - "saveLabel": "Enregistrer" + "connectButton": "Connexion" + }, + "error": { + "defaultError": "Une erreur s'est produite lors de l'enregistrement de l'appareil.", + "defaultDeletionError": "Une erreur s'est produite lors de la suppression de l'appareil.", + "conflictError": "L'appareil actuel est déjà dans Gladys." } } }, diff --git a/front/src/routes/integration/all/ewelink/EweLinkDeviceBox.jsx b/front/src/routes/integration/all/ewelink/EweLinkDeviceBox.jsx index 96faf9f9f5..990795de13 100644 --- a/front/src/routes/integration/all/ewelink/EweLinkDeviceBox.jsx +++ b/front/src/routes/integration/all/ewelink/EweLinkDeviceBox.jsx @@ -68,8 +68,8 @@ class EweLinkDeviceBox extends Component { { loading, errorMessage, tooMuchStatesError, statesNumber } ) { const validModel = device.features && device.features.length > 0; - const online = device.params.find(param => param.name === DEVICE_ONLINE).value === '1'; - const firmware = device.params.find(param => param.name === DEVICE_FIRMWARE).value; + const online = device.params.find(param => param.name === DEVICE_PARAMS.ONLINE).value === '1'; + const firmware = device.params.find(param => param.name === DEVICE_PARAMS.FIRMWARE).value; return (
diff --git a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx index 9ac1d6ddd0..2db85b00a5 100644 --- a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx +++ b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx @@ -2,7 +2,7 @@ import { Component } from 'preact'; import { Text, Localizer } from 'preact-i18n'; import cx from 'classnames'; import { DeviceFeatureCategoriesIcon } from '../../../../utils/consts'; -import { DEVICE_FIRMWARE, DEVICE_ONLINE } from '../../../../../../server/services/overkiz/lib/utils/overkiz.constants'; +import { DEVICE_PARAMS } from '../../../../../../server/services/overkiz/lib/utils/overkiz.constants'; import get from 'get-value'; class OverkizDeviceBox extends Component { @@ -53,8 +53,8 @@ class OverkizDeviceBox extends Component { }; render({ deviceIndex, device, housesWithRooms, editable, ...props }, { loading, errorMessage }) { - const online = device.params.find(param => param.name === DEVICE_ONLINE).value === '1'; - const firmware = device.params.find(param => param.name === DEVICE_FIRMWARE).value; + const online = device.params.find(param => param.name === DEVICE_PARAMS.ONLINE).value === '1'; + const firmware = device.params.find(param => param.name === DEVICE_PARAMS.FIRMWARE).value; return (
@@ -67,7 +67,7 @@ class OverkizDeviceBox extends Component {
- {device.params.find(param => param.name === DEVICE_FIRMWARE) && ( + {firmware && (
{`Firmware: ${firmware}`}
)}
diff --git a/front/src/routes/integration/all/overkiz/OverkizPage.jsx b/front/src/routes/integration/all/overkiz/OverkizPage.jsx index c5a934f67c..4537eb8262 100644 --- a/front/src/routes/integration/all/overkiz/OverkizPage.jsx +++ b/front/src/routes/integration/all/overkiz/OverkizPage.jsx @@ -37,14 +37,14 @@ const OverkizPage = ({ children, user }) => ( - + store.setState({ connectOverkizStatus: undefined }), 3000); } catch (e) { store.setState({ - connectOverkizStatus: RequestStatus.Error, - passwordChanges: false + saveConfigurationStatus: RequestStatus.Error }); } }, diff --git a/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx b/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx index 3b94d58cf3..58f6f453d6 100644 --- a/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx +++ b/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx @@ -32,8 +32,8 @@ const DeviceTab = ({ children, ...props }) => ( {props.errorLoading && (

- - + +

)} diff --git a/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx b/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx new file mode 100644 index 0000000000..ba45187b71 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx @@ -0,0 +1,136 @@ +import { Component } from 'preact'; +import { Text, Localizer } from 'preact-i18n'; +import cx from 'classnames'; + +import { RequestStatus } from '../../../../../utils/consts'; + +class SetupTab extends Component { + + updateOverkizType = e => { + this.props.updateConfiguration({ overkizType: e.target.value }); + }; + + updateOverkizUsername = e => { + this.props.updateConfiguration({ overkizUsername: e.target.value }); + }; + + updateOverkizPassword = e => { + this.props.updateConfiguration({ overkizPassword: e.target.value, passwordChanges: true }); + }; + + showPassword = () => { + this.setState({ showPassword: true }); + setTimeout(() => this.setState({ showPassword: false }), 5000); + }; + + render(props, { overkizTypes, showPassword }) { + return ( +
+
+

+ +

+
+
+
+
+
+

+ +

+ {props.connectOverkizStatus === RequestStatus.Error && !props.overkizConnectionError && ( +

+ +

+ )} + {props.connectOverkizStatus === RequestStatus.Success && !props.overkizConnected && ( +

+ +

+ )} + {props.overkizConnected && ( +

+ +

+ )} + {props.overkizConnectionError && ( +

+ +

+ )} + +
+
+ + +
+ +
+ + + } + value={props.overkizUsername} + class="form-control" + onInput={this.updateOverkizUsername} + /> + +
+ +
+ + + } + value={props.overkizPassword} + class="form-control" + onInput={this.updateOverkizPassword} + /> + + + + +
+ +
+
+ +
+
+ +
+
+
+
+ ); + } +}; + +export default SetupTab; diff --git a/front/src/routes/integration/all/overkiz/setup-page/index.js b/front/src/routes/integration/all/overkiz/settings-page/index.js similarity index 65% rename from front/src/routes/integration/all/overkiz/setup-page/index.js rename to front/src/routes/integration/all/overkiz/settings-page/index.js index 51d14a29a2..c8c3a1233a 100644 --- a/front/src/routes/integration/all/overkiz/setup-page/index.js +++ b/front/src/routes/integration/all/overkiz/settings-page/index.js @@ -2,17 +2,19 @@ import { Component } from 'preact'; import { connect } from 'unistore/preact'; import actions from '../actions'; import OverkizPage from '../OverkizPage'; -import SetupTab from './SetupTab'; +import SettingsTab from './SettingsTab'; +import { SUPPORTED_SERVERS } from '../../../../../../../server/services/overkiz/lib/utils/overkiz.constants'; import { WEBSOCKET_MESSAGE_TYPES } from '../../../../../../../server/utils/constants'; @connect( - 'user,session,overkizUsername,overkizPassword,connectOverkizStatus,overkizConnected,overkizConnectionError', + 'user,session,overkizType,overkizUsername,overkizPassword,overkizGetConfigurationStatus,saveConfigurationStatus', actions ) -class OverkizSetupPage extends Component { +class OverkizSettingsTab extends Component { componentWillMount() { this.props.getIntegrationByName('overkiz'); - this.props.loadProps(); + this.props.getConfiguration(); + this.props.overkizTypes = SUPPORTED_SERVERS; this.props.session.dispatcher.addListener( WEBSOCKET_MESSAGE_TYPES.OVERKIZ.CONNECTED, this.props.displayConnectedMessage @@ -30,11 +32,11 @@ class OverkizSetupPage extends Component { render(props, {}) { return ( - - + + ); } } -export default OverkizSetupPage; +export default OverkizSettingsTab; diff --git a/front/src/routes/integration/all/overkiz/setup-page/SetupTab.jsx b/front/src/routes/integration/all/overkiz/setup-page/SetupTab.jsx deleted file mode 100644 index 979d08384a..0000000000 --- a/front/src/routes/integration/all/overkiz/setup-page/SetupTab.jsx +++ /dev/null @@ -1,93 +0,0 @@ -import { Text, Localizer } from 'preact-i18n'; -import cx from 'classnames'; - -import { RequestStatus } from '../../../../../utils/consts'; - -const SetupTab = ({ children, ...props }) => { - return ( -
-
-

- -

-
-
-
-
-
-

- -

- {props.connectOverkizStatus === RequestStatus.Error && !props.overkizConnectionError && ( -

- -

- )} - {props.connectOverkizStatus === RequestStatus.Success && !props.overkizConnected && ( -

- -

- )} - {props.overkizConnected && ( -

- -

- )} - {props.overkizConnectionError && ( -

- -

- )} - -
-
- - - } - value={props.overkizUsername} - class="form-control" - onInput={props.updateConfigration} - /> - -
- -
- - - } - value={props.overkizPassword} - class="form-control" - onInput={props.updateConfigration} - /> - -
- -
-
- -
-
-
-
-
-
-
- ); -}; - -export default SetupTab; diff --git a/server/lib/device/device.setupPoll.js b/server/lib/device/device.setupPoll.js index 04e07e8d16..61773cfbb7 100644 --- a/server/lib/device/device.setupPoll.js +++ b/server/lib/device/device.setupPoll.js @@ -6,7 +6,7 @@ const { DEVICE_POLL_FREQUENCIES_LIST } = require('../../utils/constants'); * setupPoll(); */ function setupPoll() { - DEVICE_POLL_FREQUENCIES_LIST.forEach(pollFrequency => { + DEVICE_POLL_FREQUENCIES_LIST.forEach((pollFrequency) => { setInterval(this.pollAll(pollFrequency), pollFrequency); }); } diff --git a/server/services/index.js b/server/services/index.js index cbcb716710..01ff95478d 100644 --- a/server/services/index.js +++ b/server/services/index.js @@ -17,4 +17,4 @@ module.exports.zigbee2mqtt = require('./zigbee2mqtt'); module.exports['google-actions'] = require('./google-actions'); module.exports.homekit = require('./homekit'); module.exports.broadlink = require('./broadlink'); -module.exports.overkiz = require('./overkiz'); \ No newline at end of file +module.exports.overkiz = require('./overkiz'); diff --git a/server/services/overkiz/api/overkiz.controller.js b/server/services/overkiz/api/overkiz.controller.js index 425995d761..49fd717e43 100644 --- a/server/services/overkiz/api/overkiz.controller.js +++ b/server/services/overkiz/api/overkiz.controller.js @@ -1,25 +1,48 @@ const asyncMiddleware = require('../../../api/middlewares/asyncMiddleware'); -module.exports = function OverkizController(overkizHandler) { +module.exports = function OverkizController(overkizManager) { /** - * @api {post} /api/v1/service/overkiz/connect Connect to overkiz cloud account. + * @api {get} /api/v1/service/overkiz/configuration Get Overkiz configuration + * @apiName getConfiguration + * @apiGroup Overkiz + */ + async function getConfiguration(req, res) { + const configuration = await overkizManager.getConfiguration(); + res.json(configuration); + } + + /** + * @api {post} /api/v1/service/overkiz/configuration Update Overkiz configuration + * @apiName updateConfiguration + * @apiGroup Overkiz + */ + async function updateConfiguration(req, res) { + const result = await overkizManager.updateConfiguration(req.body); + overkizManager.connect(); + res.json({ + success: result, + }); + } + + /** + * @api {post} /api/v1/service/overkiz/connect Connect to Overkiz cloud account. * @apiName save - * @apiGroup overkiz + * @apiGroup Overkiz */ async function connect(req, res) { - await overkizHandler.connect(); + await overkizManager.connect(); res.json({ success: true, }); } /** - * @api {get} /api/v1/service/overkiz/status Get overkiz connection status. + * @api {get} /api/v1/service/overkiz/status Get Overkiz connection status. * @apiName status - * @apiGroup overkiz + * @apiGroup Overkiz */ async function status(req, res) { - const response = overkizHandler.status(); + const response = overkizManager.status(); res.json(response); } @@ -29,7 +52,7 @@ module.exports = function OverkizController(overkizHandler) { * @apiGroup overkiz */ async function getDevices(req, res) { - const devices = await overkizHandler.getOverkizDevices(); + const devices = await overkizManager.getOverkizDevices(); res.json(devices); } @@ -39,12 +62,20 @@ module.exports = function OverkizController(overkizHandler) { * @apiGroup overkiz */ async function discoverDevices(req, res) { - await overkizHandler.syncOverkizDevices(); - const devices = await overkizHandler.getOverkizDevices(); + await overkizManager.syncOverkizDevices(); + const devices = await overkizManager.getOverkizDevices(); res.json(devices); } return { + 'get /api/v1/service/overkiz/configuration': { + authenticated: true, + controller: asyncMiddleware(getConfiguration), + }, + 'post /api/v1/service/overkiz/configuration': { + authenticated: true, + controller: asyncMiddleware(updateConfiguration), + }, 'post /api/v1/service/overkiz/connect': { authenticated: true, admin: true, diff --git a/server/services/overkiz/lib/commands/overkiz.config.js b/server/services/overkiz/lib/commands/overkiz.config.js deleted file mode 100644 index e838377259..0000000000 --- a/server/services/overkiz/lib/commands/overkiz.config.js +++ /dev/null @@ -1,34 +0,0 @@ -const logger = require('../../../../utils/logger'); - -/** - * @description Overkiz config - * @example - * overkiz.config(); - */ -function config() { - logger.debug(`Overkiz : Config`); -} - -/** - * @description Enable Discovery - * @example - * overkiz.enableDiscovery(); - */ -function enableDiscovery() { - logger.debug(`Overkiz : Enable discovery`); -} - -/** - * @description Disable Discovery - * @example - * overkiz.disableDiscovery(); - */ -function disableDiscovery() { - logger.debug(`Overkiz : Disable discovery`); -} - -module.exports = { - config, - enableDiscovery, - disableDiscovery, -}; diff --git a/server/services/overkiz/lib/commands/overkiz.configuration.js b/server/services/overkiz/lib/commands/overkiz.configuration.js new file mode 100644 index 0000000000..fac891af73 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.configuration.js @@ -0,0 +1,56 @@ +const logger = require('../../../../utils/logger'); +const { OVERKIZ_SERVER_PARAM } = require('../utils/overkiz.constants'); + +/** + * @description Get Overkiz configuration. + * @returns {Promise} Return Overkiz configuration. + * @example + * overkiz.getConfiguration(); + */ +async function getConfiguration() { + logger.debug(`Overkiz : Config`); + + const overkizType = await this.gladys.variable.getValue(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE, this.serviceId); + const overkizUsername = await this.gladys.variable.getValue( + OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_USERNAME, + this.serviceId, + ); + const overkizPassword = await this.gladys.variable.getValue( + OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_PASSWORD, + this.serviceId, + ); + return { + overkizType, + overkizUsername, + overkizPassword, + }; +} + +/** + * @description Update Overkiz configuration. + * @param {Object} configuration - The Overkiz configuration. + * @example + * overkiz.updateConfiguration(); + */ +async function updateConfiguration(configuration) { + logger.debug(`Overkiz : Update configuration`); + + const { overkizType, overkizUsername, overkizPassword } = configuration; + + if (overkizType) { + await this.gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE, overkizType, this.serviceId); + } + + if (overkizUsername) { + await this.gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_USERNAME, overkizUsername, this.serviceId); + } + + if (overkizPassword) { + await this.gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_PASSWORD, overkizPassword, this.serviceId); + } +} + +module.exports = { + getConfiguration, + updateConfiguration, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js index 0678f266f8..bdcded0da9 100644 --- a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js +++ b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js @@ -5,12 +5,12 @@ const { DEVICE_POLL_FREQUENCIES, } = require('../../../../utils/constants'); const { - DEVICE_ONLINE, - DEVICE_FIRMWARE, + DEVICE_PARAMS, DEVICE_UID_CLASSES, DEVICE_STATES, DEVICE_TYPES, - HEATING_LEVELS, + HEATING_MODES, + HEATING_STATES, } = require('../utils/overkiz.constants'); const { getDeviceName, getDeviceFeatureExternalId, getDeviceExternalId } = require('../utils/overkiz.externalId'); @@ -54,13 +54,17 @@ async function getOverkizDevices() { features: [], params: [ { - name: DEVICE_ONLINE, + name: DEVICE_PARAMS.ONLINE, value: states[DEVICE_STATES.STATUS_STATE], }, { - name: DEVICE_FIRMWARE, + name: DEVICE_PARAMS.FIRMWARE, value: attributes[DEVICE_STATES.FIRMWARE_REVISION_STATE], }, + { + name: DEVICE_PARAMS.STATE, + value: states[DEVICE_STATES.OPERATING_MODE_STATE], + }, ], }; @@ -85,48 +89,65 @@ async function getOverkizDevices() { .map((node) => { const deviceURL = node.URL.includes('#') ? node.URL.substring(0, node.URL.indexOf('#')) : node.URL; const newDevice = newDevices[deviceURL]; + const operatingModeState = newDevice.params.find((param) => param.name === DEVICE_PARAMS.STATE).value; const newFeature = { // rawOverkizDevice: node, }; if (node.uiClass === DEVICE_UID_CLASSES.HEATER) { - newDevice.features.push({ - ...newFeature, - name: `Mode`, - selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.HEATING_LEVEL_STATE}`, - external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.HEATING_LEVEL_STATE), - category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, - type: DEVICE_FEATURE_TYPES.THERMOSTAT.MODE, - read_only: false, - has_feedback: true, - min: 0, - max: HEATING_LEVELS.length - 1, - }); - newDevice.features.push({ - ...newFeature, - name: `Comfort mode temperature`, - selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.COMFORT_TEMPERATURE_STATE}`, - external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.COMFORT_TEMPERATURE_STATE), - category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, - type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, - read_only: false, - unit: DEVICE_FEATURE_UNITS.CELSIUS, - has_feedback: true, - min: 0, - max: 40, - }); - newDevice.features.push({ - ...newFeature, - name: `Eco mode temperature`, - selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.ECO_TEMPERATURE_STATE}`, - external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.ECO_TEMPERATURE_STATE), - category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, - type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, - read_only: false, - unit: DEVICE_FEATURE_UNITS.CELSIUS, - has_feedback: true, - min: 0, - max: 40, - }); + if (operatingModeState === HEATING_STATES.PROG) { + newDevice.features.push({ + ...newFeature, + name: `Mode`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.HEATING_LEVEL_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.HEATING_LEVEL_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.MODE, + read_only: false, + has_feedback: true, + min: 0, + max: HEATING_MODES.length - 1, + }); + newDevice.features.push({ + ...newFeature, + name: `Comfort mode temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.COMFORT_TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.COMFORT_TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, + read_only: false, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }); + newDevice.features.push({ + ...newFeature, + name: `Eco mode temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.ECO_TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.ECO_TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, + read_only: false, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }); + } else if (operatingModeState === HEATING_STATES.BASIC) { + newDevice.features.push({ + ...newFeature, + name: `Temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.TARGET_TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.TARGET_TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, + read_only: false, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }); + } } else if (node.uiClass === DEVICE_UID_CLASSES.TEMPERATURE) { newDevice.features.push({ ...newFeature, diff --git a/server/services/overkiz/lib/index.js b/server/services/overkiz/lib/index.js index 7a1f7c8d49..dd451f3768 100644 --- a/server/services/overkiz/lib/index.js +++ b/server/services/overkiz/lib/index.js @@ -1,7 +1,7 @@ const Bottleneck = require('bottleneck/es5'); const cron = require('node-cron'); -const { enableDiscovery, disableDiscovery, config } = require('./commands/overkiz.config'); +const { getConfiguration, updateConfiguration } = require('./commands/overkiz.configuration'); const { connect } = require('./commands/overkiz.connect'); const { disconnect } = require('./commands/overkiz.disconnect'); const { getDevicesStates } = require('./commands/overkiz.getDevicesStates'); @@ -20,7 +20,7 @@ const setValueLimiter = new Bottleneck({ minTime: 100, // 100 ms }); -const OverkizHandler = function OverkizHandler(gladys, serviceId) { +const OverkizManager = function OverkizManager(gladys, serviceId) { this.gladys = gladys; this.serviceId = serviceId; this.eventManager = gladys.event; @@ -30,14 +30,13 @@ const OverkizHandler = function OverkizHandler(gladys, serviceId) { this.scanInProgress = false; }; -OverkizHandler.prototype.connect = connect; -OverkizHandler.prototype.disconnect = disconnect; -OverkizHandler.prototype.syncOverkizDevices = syncOverkizDevices; -OverkizHandler.prototype.getOverkizDevices = getOverkizDevices; -OverkizHandler.prototype.poll = pollLimiter.wrap(getDevicesStates); -OverkizHandler.prototype.setValue = setValueLimiter.wrap(setValue); -OverkizHandler.prototype.enableDiscovery = enableDiscovery; -OverkizHandler.prototype.disableDiscovery = disableDiscovery; -OverkizHandler.prototype.config = config; +OverkizManager.prototype.connect = connect; +OverkizManager.prototype.disconnect = disconnect; +OverkizManager.prototype.syncOverkizDevices = syncOverkizDevices; +OverkizManager.prototype.getOverkizDevices = getOverkizDevices; +OverkizManager.prototype.poll = pollLimiter.wrap(getDevicesStates); +OverkizManager.prototype.setValue = setValueLimiter.wrap(setValue); +OverkizManager.prototype.getConfiguration = getConfiguration; +OverkizManager.prototype.updateConfiguration = updateConfiguration; -module.exports = OverkizHandler; +module.exports = OverkizManager; diff --git a/server/services/overkiz/lib/utils/overkiz.bindValue.js b/server/services/overkiz/lib/utils/overkiz.bindValue.js index 9987ac0c9f..a8e4ce8436 100644 --- a/server/services/overkiz/lib/utils/overkiz.bindValue.js +++ b/server/services/overkiz/lib/utils/overkiz.bindValue.js @@ -1,4 +1,4 @@ -const { DEVICE_STATES, HEATING_LEVELS } = require('./overkiz.constants'); +const { DEVICE_STATES, HEATING_MODES } = require('./overkiz.constants'); const { getNodeStateInfoByExternalId } = require('./overkiz.externalId'); /** @@ -16,7 +16,7 @@ function bindValue(device, deviceFeature, value) { return value === 0 ? 'noPersonInside' : 'personInside'; } if (state === DEVICE_STATES.HEATING_LEVEL_STATE) { - return HEATING_LEVELS[value]; + return HEATING_MODES[value]; } if (state === DEVICE_STATES.COMFORT_TEMPERATURE_STATE || state === DEVICE_STATES.ECO_TEMPERATURE_STATE) { return parseFloat(value); @@ -38,7 +38,7 @@ function unbindValue(device, stateName, stateValue) { return stateValue === 'noPersonInside' ? 0 : 1; } if (stateName === DEVICE_STATES.HEATING_LEVEL_STATE) { - return HEATING_LEVELS.indexOf(stateValue); + return HEATING_MODES.indexOf(stateValue); } return stateValue; } diff --git a/server/services/overkiz/lib/utils/overkiz.constants.js b/server/services/overkiz/lib/utils/overkiz.constants.js index 7f8ccbec82..0aa068edf9 100644 --- a/server/services/overkiz/lib/utils/overkiz.constants.js +++ b/server/services/overkiz/lib/utils/overkiz.constants.js @@ -1,5 +1,8 @@ -const DEVICE_FIRMWARE = 'FIRMWARE'; -const DEVICE_ONLINE = 'ONLINE'; +const DEVICE_PARAMS = { + FIRMWARE: 'FIRMWARE', + ONLINE: 'ONLINE', + STATE: 'STATE', +}; const SUPPORTED_SERVERS = { atlantic_cozytouch: { @@ -115,10 +118,12 @@ const DEVICE_STATES = { HEATING_LEVEL_STATE: 'io:TargetHeatingLevelState', OCCUPANCY_STATE: 'core:OccupancyState', TEMPERATURE_STATE: 'core:TemperatureState', + TARGET_TEMPERATURE_STATE: 'core:TargetTemperatureState', COMFORT_TEMPERATURE_STATE: 'core:ComfortRoomTemperatureState', ECO_TEMPERATURE_STATE: 'io:EffectiveTemperatureSetpointState', // 'core:EcoRoomTemperatureState', ON_OFF_STATE: 'core:OnOffState', - ELECTRIC_ENERGY_CONSUMTION_STATE: 'core:ElectricEnergyConsumptionState', + ELECTRIC_ENERGY_CONSUMPTION_STATE: 'core:ElectricEnergyConsumptionState', + OPERATING_MODE_STATE: 'core:OperatingModeState', }; const DEVICE_COMMANDS = { @@ -132,17 +137,24 @@ const DEVICE_COMMANDS = { REFRESH_COMFORT_TEMPERATURE: 'refreshComfortTemperature', }; -const HEATING_LEVELS = ['off', 'frost-protection', 'eco', 'comfort-2', 'comfort-1', 'comfort']; +const HEATING_MODES = ['off', 'frost-protection', 'eco', 'comfort-2', 'comfort-1', 'comfort']; + +const HEATING_STATES = { + STOPPED: 'standby', + BASIC: 'basic', + PROG: 'internal', // mode suivant un planing horaire + AUTO: 'auto', +}; module.exports = { SUPPORTED_SERVERS, OVERKIZ_SERVER_PARAM, OVERKIZ_API, - DEVICE_FIRMWARE, - DEVICE_ONLINE, + DEVICE_PARAMS, DEVICE_TYPES, DEVICE_UID_CLASSES, DEVICE_STATES, DEVICE_COMMANDS, - HEATING_LEVELS, + HEATING_MODES, + HEATING_STATES, }; From 93baf60bd1a494649413ef2e51d4d4c0f3d0750a Mon Sep 17 00:00:00 2001 From: POCHET Romuald Date: Wed, 3 May 2023 13:30:44 +0200 Subject: [PATCH 10/40] Initial commit --- .../src/assets/integrations/cover/overkiz.jpg | Bin 0 -> 33570 bytes front/src/components/app.jsx | 6 + front/src/config/i18n/en.json | 53 + front/src/config/i18n/fr.json | 53 + front/src/config/integrations/devices.json | 4 + .../all/overkiz/OverkizDeviceBox.jsx | 192 ++++ .../integration/all/overkiz/OverkizPage.jsx | 72 ++ .../routes/integration/all/overkiz/actions.js | 244 ++++ .../all/overkiz/device-page/DeviceTab.jsx | 70 ++ .../all/overkiz/device-page/EmptyState.jsx | 23 + .../all/overkiz/device-page/index.js | 24 + .../all/overkiz/device-page/style.css | 7 + .../all/overkiz/discover-page/DiscoverTab.jsx | 62 + .../all/overkiz/discover-page/EmptyState.jsx | 13 + .../all/overkiz/discover-page/index.js | 24 + .../all/overkiz/discover-page/style.css | 7 + .../all/overkiz/edit-page/index.js | 22 + .../all/overkiz/settings-page/SettingsTab.jsx | 136 +++ .../all/overkiz/settings-page/index.js | 42 + server/services/index.js | 1 + server/services/overkiz/README.md | 3 + .../overkiz/api/overkiz.controller.js | 97 ++ server/services/overkiz/index.js | 63 + .../lib/commands/overkiz.configuration.js | 56 + .../overkiz/lib/commands/overkiz.connect.js | 66 ++ .../lib/commands/overkiz.disconnect.js | 19 + .../lib/commands/overkiz.getDevicesStates.js | 55 + .../lib/commands/overkiz.getOverkizDevices.js | 194 ++++ .../lib/commands/overkiz.sendCommand.js | 114 ++ .../overkiz/lib/commands/overkiz.setValue.js | 38 + .../commands/overkiz.syncOverkizDevices.js | 64 ++ server/services/overkiz/lib/index.js | 42 + .../overkiz/lib/utils/overkiz.bindValue.js | 49 + .../overkiz/lib/utils/overkiz.constants.js | 160 +++ .../overkiz/lib/utils/overkiz.externalId.js | 72 ++ server/services/overkiz/package-lock.json | 1014 +++++++++++++++++ server/services/overkiz/package.json | 23 + 37 files changed, 3184 insertions(+) create mode 100644 front/src/assets/integrations/cover/overkiz.jpg create mode 100644 front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx create mode 100644 front/src/routes/integration/all/overkiz/OverkizPage.jsx create mode 100644 front/src/routes/integration/all/overkiz/actions.js create mode 100644 front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx create mode 100644 front/src/routes/integration/all/overkiz/device-page/EmptyState.jsx create mode 100644 front/src/routes/integration/all/overkiz/device-page/index.js create mode 100644 front/src/routes/integration/all/overkiz/device-page/style.css create mode 100644 front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx create mode 100644 front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx create mode 100644 front/src/routes/integration/all/overkiz/discover-page/index.js create mode 100644 front/src/routes/integration/all/overkiz/discover-page/style.css create mode 100644 front/src/routes/integration/all/overkiz/edit-page/index.js create mode 100644 front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx create mode 100644 front/src/routes/integration/all/overkiz/settings-page/index.js create mode 100644 server/services/overkiz/README.md create mode 100644 server/services/overkiz/api/overkiz.controller.js create mode 100644 server/services/overkiz/index.js create mode 100644 server/services/overkiz/lib/commands/overkiz.configuration.js create mode 100644 server/services/overkiz/lib/commands/overkiz.connect.js create mode 100644 server/services/overkiz/lib/commands/overkiz.disconnect.js create mode 100644 server/services/overkiz/lib/commands/overkiz.getDevicesStates.js create mode 100644 server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js create mode 100644 server/services/overkiz/lib/commands/overkiz.sendCommand.js create mode 100644 server/services/overkiz/lib/commands/overkiz.setValue.js create mode 100644 server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js create mode 100644 server/services/overkiz/lib/index.js create mode 100644 server/services/overkiz/lib/utils/overkiz.bindValue.js create mode 100644 server/services/overkiz/lib/utils/overkiz.constants.js create mode 100644 server/services/overkiz/lib/utils/overkiz.externalId.js create mode 100644 server/services/overkiz/package-lock.json create mode 100644 server/services/overkiz/package.json diff --git a/front/src/assets/integrations/cover/overkiz.jpg b/front/src/assets/integrations/cover/overkiz.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3acdb0f4367e2140f166410e5fba8c8afe6fafa5 GIT binary patch literal 33570 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 N3((y@H2pdKKLGZif3*Mr literal 0 HcmV?d00001 diff --git a/front/src/components/app.jsx b/front/src/components/app.jsx index ed8d4beceb..8e7234486b 100644 --- a/front/src/components/app.jsx +++ b/front/src/components/app.jsx @@ -132,6 +132,12 @@ import EweLinkSetupPage from '../routes/integration/all/ewelink/setup-page'; // OpenAI integration import OpenAIPage from '../routes/integration/all/openai/index'; +// Overkiz +import OverkizPage from '../routes/integration/all/overkiz/device-page'; +import OverkizEditPage from '../routes/integration/all/overkiz/edit-page'; +import OverkizDiscoverPage from '../routes/integration/all/overkiz/discover-page'; +import OverkizSetupPage from '../routes/integration/all/overkiz/settings-page'; + const defaultState = getDefaultState(); const store = createStore(defaultState); diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index 17158a2081..3929910005 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -1149,6 +1149,59 @@ "notOnGladysPlus": "As ChatGPT API is not free, this integration is only available to Gladys Plus users.", "subscribeToGladysPlus": "Click here to subscribe to Gladys Plus.", "licenseShouldBeActive": "This integration is only available to users with an active license (at least one payment). For trial users, please contact us on the forum or email." + }, + "overkiz": { + "title": "Overkiz", + "description": "Control your Overkiz devices.", + "deviceTab": "Devices", + "discoverTab": "Overkiz discover", + "discoverDeviceDescr": "", + "settingsTab": "Configuration", + "documentation": "Overkiz documentation", + "device": { + "title": "", + "search": "", + "noDeviceFound": "", + "nameLabel": "", + "namePlaceholder": "", + "modelLabel": "", + "roomLabel": "", + "featuresLabel": "", + "createButton": "Save", + "updateButton": "Update", + "deleteButton": "Delete", + "editButton": "" + }, + "status": { + "notConnected": "", + "setupPageLink": "" + }, + "discover": { + "title": "Overkiz devices in Gladys", + "scan": "Search devices", + "description": "", + "noDeviceFound": "No Overkiz device found." + }, + "settings": { + "title": "Overkiz configuration", + "overkizDescription": "You can connect Gladys to your Overkiz cloud account to command the associated devices.", + "typeLabel": "Type", + "typePlaceholder": "Enter Overkiz type", + "userLabel": "Username", + "userPlaceholder": "Enter Overkiz username", + "passwordLabel": "Password", + "passwordPlaceholder": "Enter Overkiz password", + "connectButton": "Connection", + "error": "An error occured while saving configuration.", + "connecting": "Configuration saved. Now connecting to your Overkiz cloud account...", + "connected": "Connected to the Overkiz cloud account with success !", + "connectionError": "Error while connecting, please check your configuration." + }, + "error": { + "defaultError": "There was an error saving the device.", + "defaultDeletionError": "There was an error deleting the device.", + "conflictError": "Current device is already in Gladys." + } } }, "editScene": { diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index 355305b4d9..14fd8f6620 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -1149,6 +1149,59 @@ "notOnGladysPlus": "L'API ChatGPT étant payante, cette intégration est proposée via Gladys Plus uniquement.", "subscribeToGladysPlus": "Cliquez-ici pour souscrire à Gladys Plus.", "licenseShouldBeActive": "Cette intégration n'est disponible qu'aux utilisateurs Gladys Plus dont l'abonnement est actuellement actif avec au moins un paiement. Pour les utilisateurs en périodes d'essai, merci de me contacter sur le forum ou par email !" + }, + "overkiz": { + "title": "Overkiz", + "description": "Contrôler vos appareils Overkiz.", + "deviceTab": "Appareils", + "discoverTab": "Découverte Overkiz", + "discoverDeviceDescr": "", + "settingsTab": "Configuration", + "documentation": "Documentation Overkiz", + "device": { + "title": "", + "search": "", + "noDeviceFound": "Aucun périphérique Overkiz détecté.", + "nameLabel": "Nom de l'appareil", + "namePlaceholder": "Entrez le nom de votre appareil", + "modelLabel": "Modèle", + "roomLabel": "Pièce", + "createButton": "Sauvegarder", + "updateButton": "Mettre à jour", + "deleteButton": "Supprimer", + "featuresLabel": "", + "editButton": "" + }, + "status": { + "notConnected": "Gladys n'a pas réussi à se connecter au compte cloud Overkiz, plus d'informations sur la ", + "setupPageLink": "page de configuration Overkiz." + }, + "discover": { + "title": "Découverte Overkiz", + "scan": "Rechercher", + "description": "Les appareils Overkiz sont automatiquement découverts. Vos appareils Overkiz doivent être ajoutés à votre compte cloud Overkiz avant.", + "noDeviceFound": "Aucun périphérique Overkiz détecté." + }, + "settings": { + "title": "Configuration Overkiz", + "overkizDescription": "Vous pouvez connecter Gladys à votre compte cloud Overkiz pour commander les appareils associés.", + "error": "Une erreur s'est produite lors de la sauvegarde de la configuration.", + "connecting": "Configuration sauvegardée. Connexion à votre compte cloud Overkiz...", + "connected": "Connexion réussie au compte cloud Overkiz !", + "connectionError": "Erreur lors de la connexion, veuillez vérifier votre configuration.", + "typeLabel": "Type", + "typePlaceholder": "Entrez le type Overkiz", + "userLabel": "Nom d'utilisateur", + "userPlaceholder": "Entrez le nom d'utilisateur Overkiz", + "passwordLabel": "Mot de passe", + "passwordPlaceholder": "Entrez le mot de passe utilisateur Overkiz", + "connectButton": "Connexion" + }, + "error": { + "defaultError": "Une erreur s'est produite lors de l'enregistrement de l'appareil.", + "defaultDeletionError": "Une erreur s'est produite lors de la suppression de l'appareil.", + "conflictError": "L'appareil actuel est déjà dans Gladys." + } } }, "editScene": { diff --git a/front/src/config/integrations/devices.json b/front/src/config/integrations/devices.json index 2c784e1779..c46430d9b1 100644 --- a/front/src/config/integrations/devices.json +++ b/front/src/config/integrations/devices.json @@ -58,5 +58,9 @@ "key": "lanManager", "link": "lan-manager", "img": "/assets/integrations/cover/lan-manager.jpg" + }, + { + "key": "overkiz", + "img": "/assets/integrations/cover/overkiz.jpg" } ] diff --git a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx new file mode 100644 index 0000000000..2db85b00a5 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx @@ -0,0 +1,192 @@ +import { Component } from 'preact'; +import { Text, Localizer } from 'preact-i18n'; +import cx from 'classnames'; +import { DeviceFeatureCategoriesIcon } from '../../../../utils/consts'; +import { DEVICE_PARAMS } from '../../../../../../server/services/overkiz/lib/utils/overkiz.constants'; +import get from 'get-value'; + +class OverkizDeviceBox extends Component { + updateName = e => { + this.props.updateDeviceField(this.props.listName, this.props.deviceIndex, 'name', e.target.value); + }; + + updateRoom = e => { + this.props.updateDeviceField(this.props.listName, this.props.deviceIndex, 'room_id', e.target.value); + }; + + saveDevice = async () => { + this.setState({ + loading: true, + errorMessage: null + }); + try { + await this.props.saveDevice(this.props.listName, this.props.deviceIndex); + } catch (e) { + let errorMessage = 'integration.overkiz.error.defaultError'; + if (e.response.status === 409) { + errorMessage = 'integration.overkiz.error.conflictError'; + } + this.setState({ + errorMessage + }); + } + this.setState({ + loading: false + }); + }; + + deleteDevice = async () => { + this.setState({ + loading: true, + errorMessage: null + }); + try { + await this.props.deleteDevice(this.props.deviceIndex); + } catch (e) { + this.setState({ + errorMessage: 'integration.overkiz.error.defaultDeletionError' + }); + } + this.setState({ + loading: false + }); + }; + + render({ deviceIndex, device, housesWithRooms, editable, ...props }, { loading, errorMessage }) { + const online = device.params.find(param => param.name === DEVICE_PARAMS.ONLINE).value === '1'; + const firmware = device.params.find(param => param.name === DEVICE_PARAMS.FIRMWARE).value; + + return ( +
+
+
+ +
}> + +  {device.name} +
+
+
+ {firmware && ( +
{`Firmware: ${firmware}`}
+ )} +
+
+
+
+
+
+ {errorMessage && ( +
+ +
+ )} +
+ + + } + disabled={!editable} + /> + +
+ +
+ + +
+ + {editable && ( +
+ + +
+ )} + +
+ +
+ {device.features.map(feature => ( + + +
+ +
+
+ ))} +
+
+ +
+ {props.createButton && ( + + )} + + {props.updateButton && ( + + )} + + {props.deleteButton && ( + + )} +
+
+
+
+
+
+ ); + } +} + +export default OverkizDeviceBox; diff --git a/front/src/routes/integration/all/overkiz/OverkizPage.jsx b/front/src/routes/integration/all/overkiz/OverkizPage.jsx new file mode 100644 index 0000000000..4537eb8262 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/OverkizPage.jsx @@ -0,0 +1,72 @@ +import { Text } from 'preact-i18n'; +import { Link } from 'preact-router/match'; +import DeviceConfigurationLink from '../../../../components/documentation/DeviceConfigurationLink'; + +const OverkizPage = ({ children, user }) => ( +
+
+
+
+
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
{children}
+
+
+
+
+
+); + +export default OverkizPage; diff --git a/front/src/routes/integration/all/overkiz/actions.js b/front/src/routes/integration/all/overkiz/actions.js new file mode 100644 index 0000000000..19105ab780 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/actions.js @@ -0,0 +1,244 @@ +import update from 'immutability-helper'; +import debounce from 'debounce'; +import { RequestStatus } from '../../../../utils/consts'; +import createActionsIntegration from '../../../../actions/integration'; + +function createActions(store) { + const integrationActions = createActionsIntegration(store); + const actions = { + async getConfiguration(state) { + store.setState({ + overkizGetConfigurationStatus: RequestStatus.Getting + }); + try { + const configuration = await state.httpClient.get('/api/v1/service/overkiz/configuration'); + store.setState({ + overkizGetConfigurationStatus: RequestStatus.Success, + ...configuration + }); + } catch (e) { + store.setState({ + overkizGetConfigurationStatus: RequestStatus.Error + }); + } + }, + updateConfiguration(state, configuration) { + store.setState(configuration); + }, + async connect(state) { + await actions.disconnect(state); + await actions.saveConfiguration(state); + store.setState({ + overkizConnectStatus: RequestStatus.Getting + }); + try { + await state.httpClient.post('/api/v1/service/overkiz/connect'); + await actions.getStatus(store.getState()); + store.setState({ + overkizConnectStatus: RequestStatus.Success, + overkizConnectionInProgress: true + }); + } catch (e) { + store.setState({ + overkizConnectStatus: RequestStatus.Error + }); + } + }, + async saveConfiguration(state) { + event.preventDefault(); + store.setState({ + saveConfigurationStatus: RequestStatus.Getting + }); + + const { + overkizType, + overkizUsername, + overkizPassword, + } = state; + try { + await state.httpClient.post(`/api/v1/service/overkiz/configuration`, { + overkizType, + overkizUsername, + overkizPassword, + }); + + store.setState({ + saveConfigurationStatus: RequestStatus.Success + }); + } catch (e) { + store.setState({ + saveConfigurationStatus: RequestStatus.Error + }); + } + }, + displayConnectedMessage() { + // display 3 seconds a message "Overkiz connected" + store.setState({ + overkizConnected: true, + overkizConnectionError: undefined + }); + setTimeout( + () => + store.setState({ + overkizConnected: false, + connectOverkizStatus: undefined + }), + 3000 + ); + }, + displayOverkizError(state, error) { + store.setState({ + overkizConnected: false, + connectOverkizStatus: undefined, + overkizConnectionError: error + }); + }, + async getOverkizDevices(state) { + store.setState({ + getOverkizStatus: RequestStatus.Getting + }); + try { + const options = { + order_dir: state.getOverkizOrderDir || 'asc' + }; + if (state.overkizSearch && state.overkizSearch.length) { + options.search = state.overkizSearch; + } + + const overkizDevices = await state.httpClient.get('/api/v1/service/overkiz/device', options); + store.setState({ + overkizDevices, + getOverkizStatus: RequestStatus.Success + }); + } catch (e) { + store.setState({ + getOverkizStatus: e.message + }); + } + }, + async getDiscoveredOverkizDevices(state) { + store.setState({ + loading: true + }); + try { + const discoveredDevices = await state.httpClient.get('/api/v1/service/overkiz/discover'); + store.setState({ + discoveredDevices, + loading: false, + errorLoading: false + }); + } catch (e) { + store.setState({ + loading: false, + errorLoading: true + }); + } + }, + async discoverOverkizDevices(state) { + store.setState({ + loading: true + }); + try { + await state.httpClient.post('/api/v1/service/overkiz/discover'); + const discoveredDevices = await state.httpClient.get('/api/v1/service/overkiz/discover'); + store.setState({ + discoveredDevices, + loading: false, + errorLoading: false + }); + } catch (e) { + store.setState({ + loading: false, + errorLoading: true + }); + } + }, + async getHouses(state) { + store.setState({ + housesGetStatus: RequestStatus.Getting + }); + try { + const params = { + expand: 'rooms' + }; + const housesWithRooms = await state.httpClient.get(`/api/v1/house`, params); + store.setState({ + housesWithRooms, + housesGetStatus: RequestStatus.Success + }); + } catch (e) { + store.setState({ + housesGetStatus: RequestStatus.Error + }); + } + }, + updateDeviceField(state, listName, index, field, value) { + const devices = update(state[listName], { + [index]: { + [field]: { + $set: value + } + } + }); + store.setState({ + [listName]: devices + }); + }, + updateFeatureProperty(state, listName, deviceIndex, featureIndex, property, value) { + const devices = update(state[listName], { + [deviceIndex]: { + features: { + [featureIndex]: { + [property]: { + $set: value + } + } + } + } + }); + + store.setState({ + [listName]: devices + }); + }, + async saveDevice(state, listName, index) { + const device = state[listName][index]; + const savedDevice = await state.httpClient.post(`/api/v1/device`, device); + const devices = update(state[listName], { + $splice: [[index, 1, savedDevice]] + }); + store.setState({ + [listName]: devices + }); + }, + async deleteDevice(state, index) { + const device = state.overkizDevices[index]; + if (device.created_at) { + await state.httpClient.delete(`/api/v1/device/${device.selector}`); + } + const overkizDevices = update(state.overkizDevices, { + $splice: [[index, 1]] + }); + store.setState({ + overkizDevices + }); + }, + async search(state, e) { + store.setState({ + overkizSearch: e.target.value + }); + await actions.getOverkizDevices(store.getState()); + }, + async changeOrderDir(state, e) { + store.setState({ + getOverkizOrderDir: e.target.value + }); + await actions.getOverkizDevices(store.getState()); + } + }; + actions.debouncedSearch = debounce(actions.search, 200); + + return Object.assign({}, integrationActions, actions); +} + +export default createActions; diff --git a/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx b/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx new file mode 100644 index 0000000000..18fac2d1b9 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/device-page/DeviceTab.jsx @@ -0,0 +1,70 @@ +import { Text, Localizer } from 'preact-i18n'; +import cx from 'classnames'; + +import EmptyState from './EmptyState'; +import { RequestStatus } from '../../../../../utils/consts'; +import style from './style.css'; +import OverkizDeviceBox from '../OverkizDeviceBox'; + +const DeviceTab = ({ children, ...props }) => ( +
+
+

+ +

+
+ +
+ + + + + } + onInput={props.debouncedSearch} + /> + +
+
+
+
+
+
+
+
+ {props.overkizDevices && + props.overkizDevices.length > 0 && + props.overkizDevices.map((device, index) => ( + + ))} + {!props.overkizDevices || (props.overkizDevices.length === 0 && )} +
+
+
+
+
+); + +export default DeviceTab; diff --git a/front/src/routes/integration/all/overkiz/device-page/EmptyState.jsx b/front/src/routes/integration/all/overkiz/device-page/EmptyState.jsx new file mode 100644 index 0000000000..7b553f17a7 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/device-page/EmptyState.jsx @@ -0,0 +1,23 @@ +import { Text } from 'preact-i18n'; +import { Link } from 'preact-router/match'; +import cx from 'classnames'; +import style from './style.css'; + +const EmptyState = () => ( +
+
+ + +
+ + + + +
+
+
+); + +export default EmptyState; diff --git a/front/src/routes/integration/all/overkiz/device-page/index.js b/front/src/routes/integration/all/overkiz/device-page/index.js new file mode 100644 index 0000000000..b13f2f4b18 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/device-page/index.js @@ -0,0 +1,24 @@ +import { Component } from 'preact'; +import { connect } from 'unistore/preact'; +import actions from '../actions'; +import OverkizPage from '../OverkizPage'; +import DeviceTab from './DeviceTab'; + +@connect('user,overkizDevices,housesWithRooms,getOverkizStatus', actions) +class OverkizIntegration extends Component { + componentWillMount() { + this.props.getOverkizDevices(); + this.props.getHouses(); + this.props.getIntegrationByName('overkiz'); + } + + render(props, {}) { + return ( + + + + ); + } +} + +export default OverkizIntegration; diff --git a/front/src/routes/integration/all/overkiz/device-page/style.css b/front/src/routes/integration/all/overkiz/device-page/style.css new file mode 100644 index 0000000000..d4efd465ce --- /dev/null +++ b/front/src/routes/integration/all/overkiz/device-page/style.css @@ -0,0 +1,7 @@ +.emptyStateDivBox { + margin-top: 35px; +} + +.overkizListBody { + min-height: 200px +} diff --git a/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx b/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx new file mode 100644 index 0000000000..58f6f453d6 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/discover-page/DiscoverTab.jsx @@ -0,0 +1,62 @@ +import { Text } from 'preact-i18n'; +import { Link } from 'preact-router/match'; +import cx from 'classnames'; + +import EmptyState from './EmptyState'; +import style from './style.css'; +import OverkizDeviceBox from '../OverkizDeviceBox'; + +const DeviceTab = ({ children, ...props }) => ( +
+
+

+ +

+
+ +
+
+
+
+ +
+
+
+
+ {props.errorLoading && ( +

+ + + + +

+ )} +
+ {props.discoveredDevices && + props.discoveredDevices.map((device, index) => ( + + ))} + {!props.discoveredDevices || (props.discoveredDevices.length === 0 && )} +
+
+
+
+
+); + +export default DeviceTab; diff --git a/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx b/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx new file mode 100644 index 0000000000..d78ff0b8c7 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx @@ -0,0 +1,13 @@ +import { MarkupText } from 'preact-i18n'; +import cx from 'classnames'; +import style from './style.css'; + +const EmptyState = ({ }) => ( +
+
+ +
+
+); + +export default EmptyState; diff --git a/front/src/routes/integration/all/overkiz/discover-page/index.js b/front/src/routes/integration/all/overkiz/discover-page/index.js new file mode 100644 index 0000000000..4f8dbddb8e --- /dev/null +++ b/front/src/routes/integration/all/overkiz/discover-page/index.js @@ -0,0 +1,24 @@ +import { Component } from 'preact'; +import { connect } from 'unistore/preact'; +import actions from '../actions'; +import OverkizPage from '../OverkizPage'; +import DiscoverTab from './DiscoverTab'; + +@connect('user,session,httpClient,housesWithRooms,discoveredDevices,loading,errorLoading', actions) +class OverkizIntegration extends Component { + async componentWillMount() { + this.props.getDiscoveredOverkizDevices(); + this.props.getHouses(); + this.props.getIntegrationByName('overkiz'); + } + + render(props) { + return ( + + + + ); + } +} + +export default OverkizIntegration; diff --git a/front/src/routes/integration/all/overkiz/discover-page/style.css b/front/src/routes/integration/all/overkiz/discover-page/style.css new file mode 100644 index 0000000000..1e79fa56d5 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/discover-page/style.css @@ -0,0 +1,7 @@ +.emptyStateDivBox { + margin-top: 89px; +} + +.overkizListBody { + min-height: 200px; +} diff --git a/front/src/routes/integration/all/overkiz/edit-page/index.js b/front/src/routes/integration/all/overkiz/edit-page/index.js new file mode 100644 index 0000000000..13fff479f7 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/edit-page/index.js @@ -0,0 +1,22 @@ +import { Component } from 'preact'; +import { connect } from 'unistore/preact'; +import OverkizPage from '../OverkizPage'; +import UpdateDevice from '../../../../../components/device'; + +@connect('user,session,httpClient,currentIntegration,houses', {}) +class EditOverkizDevice extends Component { + render(props, {}) { + return ( + + + + ); + } +} + +export default EditOverkizDevice; diff --git a/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx b/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx new file mode 100644 index 0000000000..ba45187b71 --- /dev/null +++ b/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx @@ -0,0 +1,136 @@ +import { Component } from 'preact'; +import { Text, Localizer } from 'preact-i18n'; +import cx from 'classnames'; + +import { RequestStatus } from '../../../../../utils/consts'; + +class SetupTab extends Component { + + updateOverkizType = e => { + this.props.updateConfiguration({ overkizType: e.target.value }); + }; + + updateOverkizUsername = e => { + this.props.updateConfiguration({ overkizUsername: e.target.value }); + }; + + updateOverkizPassword = e => { + this.props.updateConfiguration({ overkizPassword: e.target.value, passwordChanges: true }); + }; + + showPassword = () => { + this.setState({ showPassword: true }); + setTimeout(() => this.setState({ showPassword: false }), 5000); + }; + + render(props, { overkizTypes, showPassword }) { + return ( +
+
+

+ +

+
+
+
+
+
+

+ +

+ {props.connectOverkizStatus === RequestStatus.Error && !props.overkizConnectionError && ( +

+ +

+ )} + {props.connectOverkizStatus === RequestStatus.Success && !props.overkizConnected && ( +

+ +

+ )} + {props.overkizConnected && ( +

+ +

+ )} + {props.overkizConnectionError && ( +

+ +

+ )} + +
+
+ + +
+ +
+ + + } + value={props.overkizUsername} + class="form-control" + onInput={this.updateOverkizUsername} + /> + +
+ +
+ + + } + value={props.overkizPassword} + class="form-control" + onInput={this.updateOverkizPassword} + /> + + + + +
+ +
+
+ +
+
+ +
+
+
+
+ ); + } +}; + +export default SetupTab; diff --git a/front/src/routes/integration/all/overkiz/settings-page/index.js b/front/src/routes/integration/all/overkiz/settings-page/index.js new file mode 100644 index 0000000000..c8c3a1233a --- /dev/null +++ b/front/src/routes/integration/all/overkiz/settings-page/index.js @@ -0,0 +1,42 @@ +import { Component } from 'preact'; +import { connect } from 'unistore/preact'; +import actions from '../actions'; +import OverkizPage from '../OverkizPage'; +import SettingsTab from './SettingsTab'; +import { SUPPORTED_SERVERS } from '../../../../../../../server/services/overkiz/lib/utils/overkiz.constants'; +import { WEBSOCKET_MESSAGE_TYPES } from '../../../../../../../server/utils/constants'; + +@connect( + 'user,session,overkizType,overkizUsername,overkizPassword,overkizGetConfigurationStatus,saveConfigurationStatus', + actions +) +class OverkizSettingsTab extends Component { + componentWillMount() { + this.props.getIntegrationByName('overkiz'); + this.props.getConfiguration(); + this.props.overkizTypes = SUPPORTED_SERVERS; + this.props.session.dispatcher.addListener( + WEBSOCKET_MESSAGE_TYPES.OVERKIZ.CONNECTED, + this.props.displayConnectedMessage + ); + this.props.session.dispatcher.addListener(WEBSOCKET_MESSAGE_TYPES.OVERKIZ.ERROR, this.props.displayOverkizError); + } + + componentWillUnmount() { + this.props.session.dispatcher.removeListener( + WEBSOCKET_MESSAGE_TYPES.OVERKIZ.CONNECTED, + this.props.displayConnectedMessage + ); + this.props.session.dispatcher.removeListener(WEBSOCKET_MESSAGE_TYPES.OVERKIZ.ERROR, this.props.displayOverkizError); + } + + render(props, {}) { + return ( + + + + ); + } +} + +export default OverkizSettingsTab; diff --git a/server/services/index.js b/server/services/index.js index 892d98d051..a7e5227811 100644 --- a/server/services/index.js +++ b/server/services/index.js @@ -19,3 +19,4 @@ module.exports['google-actions'] = require('./google-actions'); module.exports.homekit = require('./homekit'); module.exports.broadlink = require('./broadlink'); module.exports['lan-manager'] = require('./lan-manager'); +module.exports.overkiz = require('./overkiz'); diff --git a/server/services/overkiz/README.md b/server/services/overkiz/README.md new file mode 100644 index 0000000000..87760d38c3 --- /dev/null +++ b/server/services/overkiz/README.md @@ -0,0 +1,3 @@ +# Overkiz + +[API](https://www.overkiz.com/produit/bibliotheque-dapi/) \ No newline at end of file diff --git a/server/services/overkiz/api/overkiz.controller.js b/server/services/overkiz/api/overkiz.controller.js new file mode 100644 index 0000000000..49fd717e43 --- /dev/null +++ b/server/services/overkiz/api/overkiz.controller.js @@ -0,0 +1,97 @@ +const asyncMiddleware = require('../../../api/middlewares/asyncMiddleware'); + +module.exports = function OverkizController(overkizManager) { + /** + * @api {get} /api/v1/service/overkiz/configuration Get Overkiz configuration + * @apiName getConfiguration + * @apiGroup Overkiz + */ + async function getConfiguration(req, res) { + const configuration = await overkizManager.getConfiguration(); + res.json(configuration); + } + + /** + * @api {post} /api/v1/service/overkiz/configuration Update Overkiz configuration + * @apiName updateConfiguration + * @apiGroup Overkiz + */ + async function updateConfiguration(req, res) { + const result = await overkizManager.updateConfiguration(req.body); + overkizManager.connect(); + res.json({ + success: result, + }); + } + + /** + * @api {post} /api/v1/service/overkiz/connect Connect to Overkiz cloud account. + * @apiName save + * @apiGroup Overkiz + */ + async function connect(req, res) { + await overkizManager.connect(); + res.json({ + success: true, + }); + } + + /** + * @api {get} /api/v1/service/overkiz/status Get Overkiz connection status. + * @apiName status + * @apiGroup Overkiz + */ + async function status(req, res) { + const response = overkizManager.status(); + res.json(response); + } + + /** + * @api {get} /api/v1/service/overkiz/discover Retrieve overkiz devices from cloud. + * @apiName discover + * @apiGroup overkiz + */ + async function getDevices(req, res) { + const devices = await overkizManager.getOverkizDevices(); + res.json(devices); + } + + /** + * @api {post} /api/v1/service/overkiz/discover Scan for overkiz devices from cloud. + * @apiName discover + * @apiGroup overkiz + */ + async function discoverDevices(req, res) { + await overkizManager.syncOverkizDevices(); + const devices = await overkizManager.getOverkizDevices(); + res.json(devices); + } + + return { + 'get /api/v1/service/overkiz/configuration': { + authenticated: true, + controller: asyncMiddleware(getConfiguration), + }, + 'post /api/v1/service/overkiz/configuration': { + authenticated: true, + controller: asyncMiddleware(updateConfiguration), + }, + 'post /api/v1/service/overkiz/connect': { + authenticated: true, + admin: true, + controller: asyncMiddleware(connect), + }, + 'get /api/v1/service/overkiz/status': { + authenticated: true, + controller: status, + }, + 'get /api/v1/service/overkiz/discover': { + authenticated: true, + controller: asyncMiddleware(getDevices), + }, + 'post /api/v1/service/overkiz/discover': { + authenticated: true, + controller: asyncMiddleware(discoverDevices), + }, + }; +}; diff --git a/server/services/overkiz/index.js b/server/services/overkiz/index.js new file mode 100644 index 0000000000..5771e874d3 --- /dev/null +++ b/server/services/overkiz/index.js @@ -0,0 +1,63 @@ +const logger = require('../../utils/logger'); +const OverkizHandler = require('./lib'); +const OverkizController = require('./api/overkiz.controller'); +const { ServiceNotConfiguredError } = require('../../utils/coreErrors'); +const { OVERKIZ_SERVER_PARAM } = require('./lib/utils/overkiz.constants'); + +module.exports = function OverkizService(gladys, serviceId) { + const overkizHandler = new OverkizHandler(gladys, serviceId); + + /** + * @public + * @description This function starts the Overkiz service + * @example + * gladys.services.overkiz.start(); + */ + async function start() { + logger.info('Starting Overkiz service'); + + await gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE, 'atlantic_cozytouch', serviceId); + await gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_USERNAME, 'pochet.romuald@gmail.com', serviceId); + await gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_PASSWORD, '8Vyr7acpcozytouch', serviceId); + + // Authorization server + const overkizType = await gladys.variable.getValue(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE, serviceId); + if (!overkizType) { + throw new ServiceNotConfiguredError(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE); + } + overkizHandler.overkizType = overkizType; + + await overkizHandler.connect(); + } + + /** + * @public + * @description This function stops the Overkiz service + * @example + * gladys.services.overkiz.stop(); + */ + async function stop() { + logger.info('Stopping Overkiz service'); + + await overkizHandler.disconnect(); + } + + /** + * @public + * @description Get info if the service is used. + * @returns {Promise} Returns true if the service is used. + * @example + * gladys.services.overkiz.isUsed(); + */ + async function isUsed() { + return true; + } + + return Object.freeze({ + start, + stop, + isUsed, + device: overkizHandler, + controllers: OverkizController(overkizHandler), + }); +}; diff --git a/server/services/overkiz/lib/commands/overkiz.configuration.js b/server/services/overkiz/lib/commands/overkiz.configuration.js new file mode 100644 index 0000000000..fac891af73 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.configuration.js @@ -0,0 +1,56 @@ +const logger = require('../../../../utils/logger'); +const { OVERKIZ_SERVER_PARAM } = require('../utils/overkiz.constants'); + +/** + * @description Get Overkiz configuration. + * @returns {Promise} Return Overkiz configuration. + * @example + * overkiz.getConfiguration(); + */ +async function getConfiguration() { + logger.debug(`Overkiz : Config`); + + const overkizType = await this.gladys.variable.getValue(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE, this.serviceId); + const overkizUsername = await this.gladys.variable.getValue( + OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_USERNAME, + this.serviceId, + ); + const overkizPassword = await this.gladys.variable.getValue( + OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_PASSWORD, + this.serviceId, + ); + return { + overkizType, + overkizUsername, + overkizPassword, + }; +} + +/** + * @description Update Overkiz configuration. + * @param {Object} configuration - The Overkiz configuration. + * @example + * overkiz.updateConfiguration(); + */ +async function updateConfiguration(configuration) { + logger.debug(`Overkiz : Update configuration`); + + const { overkizType, overkizUsername, overkizPassword } = configuration; + + if (overkizType) { + await this.gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE, overkizType, this.serviceId); + } + + if (overkizUsername) { + await this.gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_USERNAME, overkizUsername, this.serviceId); + } + + if (overkizPassword) { + await this.gladys.variable.setValue(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_PASSWORD, overkizPassword, this.serviceId); + } +} + +module.exports = { + getConfiguration, + updateConfiguration, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.connect.js b/server/services/overkiz/lib/commands/overkiz.connect.js new file mode 100644 index 0000000000..7ae220ed23 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.connect.js @@ -0,0 +1,66 @@ +const { API, CozytouchLoginHandler, DefaultLoginHandler } = require('overkiz-api'); +const { WEBSOCKET_MESSAGE_TYPES, EVENTS } = require('../../../../utils/constants'); +const { ServiceNotConfiguredError } = require('../../../../utils/coreErrors'); +const logger = require('../../../../utils/logger'); +const { OVERKIZ_SERVER_PARAM, SUPPORTED_SERVERS } = require('../utils/overkiz.constants'); + +/** + * @description Connect to OverKiz server. + * @returns {Promise} Return Object of informations. + * @example + * overkiz.connect(); + */ +async function connect() { + logger.info(`Overkiz : Connecting server...`); + + const overkizType = await this.gladys.variable.getValue(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE, this.serviceId); + if (!overkizType) { + throw new ServiceNotConfiguredError(OVERKIZ_SERVER_PARAM.OVERKIZ_TYPE); + } + + const overkizUsername = await this.gladys.variable.getValue( + OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_USERNAME, + this.serviceId, + ); + if (!overkizUsername) { + throw new ServiceNotConfiguredError(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_USERNAME); + } + + const overkizUserpassword = await this.gladys.variable.getValue( + OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_PASSWORD, + this.serviceId, + ); + if (!overkizUserpassword) { + throw new ServiceNotConfiguredError(OVERKIZ_SERVER_PARAM.OVERKIZ_SERVER_PASSWORD); + } + + const overkizServer = SUPPORTED_SERVERS[overkizType]; + let platformLoginHandler; + switch (overkizType) { + case 'atlantic_cozytouch': + platformLoginHandler = new CozytouchLoginHandler(overkizUsername, overkizUserpassword); + break; + default: + platformLoginHandler = new DefaultLoginHandler(overkizUsername, overkizUserpassword); + } + this.overkizServerAPI = new API({ + host: overkizServer.host, + platformLoginHandler, + polling: { + always: false, + interval: 1000, + }, + }); + this.connected = true; + + this.eventManager.emit(EVENTS.WEBSOCKET.SEND_ALL, { + type: WEBSOCKET_MESSAGE_TYPES.OVERKIZ.CONNECTED, + payload: {}, + }); + + this.syncOverkizDevices(); +} + +module.exports = { + connect, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.disconnect.js b/server/services/overkiz/lib/commands/overkiz.disconnect.js new file mode 100644 index 0000000000..f9c2c7b050 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.disconnect.js @@ -0,0 +1,19 @@ +const logger = require('../../../../utils/logger'); + +/** + * @description Disconnect to OverKiz server. + * @returns {Promise} Return Object of informations. + * @example + * overkiz.disconnect(); + */ +async function disconnect() { + logger.info(`Overkiz : Disonnecting Overkiz...`); + + if (this.updateDevicesJob) { + this.updateDevicesJob.stop(); + } +} + +module.exports = { + disconnect, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js new file mode 100644 index 0000000000..9475e10067 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js @@ -0,0 +1,55 @@ +const logger = require('../../../../utils/logger'); +const { getDeviceFeatureExternalId, getNodeStateInfoByExternalId } = require('../utils/overkiz.externalId'); +const { unbindValue } = require('../utils/overkiz.bindValue'); +const { EVENTS, DEVICE_FEATURE_CATEGORIES } = require('../../../../utils/constants'); + +/** + * @description Update device states. + * @param {Object} device - Deviceto update states. + * @returns {Promise} Return Object of informations. + * @example + * overkiz.getDevicesStates(); + */ +async function getDevicesStates(device) { + logger.info(`Overkiz : Get device state...`); + + device.features.map(async (feature) => { + const { deviceURL } = getNodeStateInfoByExternalId(feature); + + const deviceStates = await this.overkizServerAPI.get(`setup/devices/${encodeURIComponent(deviceURL)}/states`); + + logger.info(`Overkiz : Get new device states: ${deviceURL}`); + + deviceStates.forEach((state) => { + switch (state.name) { + case 'core:ComfortRoomTemperatureState': + case 'core:EcoRoomTemperatureState': + case 'core:TargetTemperatureState': // Consigne + case 'io:EffectiveTemperatureSetpointState': + case 'io:TargetHeatingLevelState': // Mode + logger.info(`${state.name} has value ${state.value}`); + break; + default: + // + } + }); + + deviceStates.forEach((state) => { + const deviceFeatureExternalId = getDeviceFeatureExternalId({ URL: deviceURL }, state.name); + const newValueUnbind = unbindValue(device, state.name, state.value); + const deviceFeature = this.gladys.stateManager.get('deviceFeatureByExternalId', deviceFeatureExternalId); + if (deviceFeature) { + if (deviceFeature.category !== DEVICE_FEATURE_CATEGORIES.PRESENCE_SENSOR || newValueUnbind !== 0) { + this.eventManager.emit(EVENTS.DEVICE.NEW_STATE, { + device_feature_external_id: deviceFeatureExternalId, + state: newValueUnbind, + }); + } + } + }); + }); +} + +module.exports = { + getDevicesStates, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js new file mode 100644 index 0000000000..bdcded0da9 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.getOverkizDevices.js @@ -0,0 +1,194 @@ +const { + DEVICE_FEATURE_CATEGORIES, + DEVICE_FEATURE_UNITS, + DEVICE_FEATURE_TYPES, + DEVICE_POLL_FREQUENCIES, +} = require('../../../../utils/constants'); +const { + DEVICE_PARAMS, + DEVICE_UID_CLASSES, + DEVICE_STATES, + DEVICE_TYPES, + HEATING_MODES, + HEATING_STATES, +} = require('../utils/overkiz.constants'); +const { getDeviceName, getDeviceFeatureExternalId, getDeviceExternalId } = require('../utils/overkiz.externalId'); + +/** + * @description Return array of Devices. + * @returns {Promise} Return list of devices. + * @example + * const devices = overkizHandler.getDevices(); + */ +async function getOverkizDevices() { + const deviceOids = Object.keys(this.devices); + + // Search for main device (non-pod system device) + const newDevices = deviceOids + .map((deviceOid) => ({ id: deviceOid, ...this.devices[deviceOid] })) + .filter((node) => node.type === DEVICE_TYPES.SYSTEM) + .filter((node) => node.uiClass !== DEVICE_UID_CLASSES.POD) + .map((node) => { + const states = node.states.reduce((map, obj) => { + map[obj.name] = obj.value; + return map; + }, {}); + + const attributes = node.attributes.reduce((map, obj) => { + map[obj.name] = obj.value; + return map; + }, {}); + + const newDevice = { + name: getDeviceName(node), + model: `${states[DEVICE_STATES.MODEL_STATE]} ${states[DEVICE_STATES.POWER_STATE]}W (${ + states[DEVICE_STATES.MANUFACTURER_NAME_STATE] + })`, + service_id: this.serviceId, + external_id: getDeviceExternalId(node), + updatable: true, + ready: node.available && node.enabled, + rawOverkizDevice: node, + should_poll: true, + poll_frequency: DEVICE_POLL_FREQUENCIES.EVERY_5_MINUTES, + features: [], + params: [ + { + name: DEVICE_PARAMS.ONLINE, + value: states[DEVICE_STATES.STATUS_STATE], + }, + { + name: DEVICE_PARAMS.FIRMWARE, + value: attributes[DEVICE_STATES.FIRMWARE_REVISION_STATE], + }, + { + name: DEVICE_PARAMS.STATE, + value: states[DEVICE_STATES.OPERATING_MODE_STATE], + }, + ], + }; + + return newDevice; + }) + .reduce((map, obj) => { + // Remove # to get all nodes from the same physical device + const deviceURL = obj.rawOverkizDevice.URL.includes('#') + ? obj.rawOverkizDevice.URL.substring(0, obj.rawOverkizDevice.URL.indexOf('#')) + : obj.rawOverkizDevice.URL; + map[deviceURL] = obj; + return map; + }, {}); + + // Search for device associated to main device (same base URL) + deviceOids + .map((deviceOid) => ({ id: deviceOid, ...this.devices[deviceOid] })) + .filter((node) => { + const deviceURL = node.URL.includes('#') ? node.URL.substring(0, node.URL.indexOf('#')) : node.URL; + return newDevices[deviceURL] !== undefined; + }) + .map((node) => { + const deviceURL = node.URL.includes('#') ? node.URL.substring(0, node.URL.indexOf('#')) : node.URL; + const newDevice = newDevices[deviceURL]; + const operatingModeState = newDevice.params.find((param) => param.name === DEVICE_PARAMS.STATE).value; + const newFeature = { + // rawOverkizDevice: node, + }; + if (node.uiClass === DEVICE_UID_CLASSES.HEATER) { + if (operatingModeState === HEATING_STATES.PROG) { + newDevice.features.push({ + ...newFeature, + name: `Mode`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.HEATING_LEVEL_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.HEATING_LEVEL_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.MODE, + read_only: false, + has_feedback: true, + min: 0, + max: HEATING_MODES.length - 1, + }); + newDevice.features.push({ + ...newFeature, + name: `Comfort mode temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.COMFORT_TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.COMFORT_TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, + read_only: false, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }); + newDevice.features.push({ + ...newFeature, + name: `Eco mode temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.ECO_TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.ECO_TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, + read_only: false, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }); + } else if (operatingModeState === HEATING_STATES.BASIC) { + newDevice.features.push({ + ...newFeature, + name: `Temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.TARGET_TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.TARGET_TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.THERMOSTAT, + type: DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, + read_only: false, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }); + } + } else if (node.uiClass === DEVICE_UID_CLASSES.TEMPERATURE) { + newDevice.features.push({ + ...newFeature, + name: `Temperature`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.TEMPERATURE_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.TEMPERATURE_STATE), + category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR, + type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL, + read_only: true, + unit: DEVICE_FEATURE_UNITS.CELSIUS, + has_feedback: true, + min: 0, + max: 40, + }); + } else if (node.uiClass === DEVICE_UID_CLASSES.OCCUPANCY) { + newDevice.features.push({ + ...newFeature, + name: `Occupancy`, + selector: `overkiz-${newDevice.rawOverkizDevice.URL}-state-${DEVICE_STATES.OCCUPANCY_STATE}`, + external_id: getDeviceFeatureExternalId(node, DEVICE_STATES.OCCUPANCY_STATE), + category: DEVICE_FEATURE_CATEGORIES.PRESENCE_SENSOR, + type: DEVICE_FEATURE_TYPES.SENSOR.PUSH, + min: 0, + max: 1, + read_only: true, + has_feedback: false, + keep_history: true, + }); + } + + return newDevice; + }); + + const newDevicesOids = Object.keys(newDevices); + return newDevicesOids + .map((newDevicesOid) => ({ ...newDevices[newDevicesOid] })) + .sort((a, b) => { + return b.ready - a.ready || a.rawOverkizDevice.id - b.rawOverkizDevice.id; + }); +} + +module.exports = { + getOverkizDevices, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.sendCommand.js b/server/services/overkiz/lib/commands/overkiz.sendCommand.js new file mode 100644 index 0000000000..24d1404044 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.sendCommand.js @@ -0,0 +1,114 @@ +const logger = require('../../../../utils/logger'); + +/** + * @description Connect to OverKiz server. + * @returns {Promise} Return state of Execution. + * @example + * overkiz.getExecutionStates(); + */ +/* async function getExecutionStates() { + const response = await retry( + async (bail) => { + const tryResponse = await axios.get(`${this.overkizServer.endpoint}exec/current`, { + headers: { + 'Cache-Control': 'no-cache', + Host: this.overkizServer.endpoint.substring( + this.overkizServer.endpoint.indexOf('/') + 2, + this.overkizServer.endpoint.indexOf('/', 8), + ), + Connection: 'Keep-Alive', + Cookie: `JSESSIONID=${this.sessionCookie}`, + }, + }); + return tryResponse; + }, + { + retries: 5, + onRetry: async (err, num) => { + if (err.response && err.response.status === 401) { + await connect.bind(this)(); + logger.info(`Overkiz : Connecting Overkiz server...`); + } else { + throw err; + } + }, + }, + ); + + return response; +} */ + +/** + * @description Connect to OverKiz server. + * @param {string} execId - Execution Id. + * @returns {Promise} Return state of Execution. + * @example + * overkiz.getExecutionState('01234'); + */ +/* async function getExecutionState(execId) { + const response = await retry( + async (bail) => { + const tryResponse = await axios.get(`${this.overkizServer.endpoint}exec/current/${execId}`, { + headers: { + 'Cache-Control': 'no-cache', + Host: this.overkizServer.endpoint.substring( + this.overkizServer.endpoint.indexOf('/') + 2, + this.overkizServer.endpoint.indexOf('/', 8), + ), + Connection: 'Keep-Alive', + Cookie: `JSESSIONID=${this.sessionCookie}`, + }, + }); + return tryResponse; + }, + { + retries: 5, + onRetry: async (err, num) => { + if (err.response && err.response.status === 401) { + await connect.bind(this)(); + logger.info(`Overkiz : Connecting Overkiz server...`); + } else { + throw err; + } + }, + }, + ); + + return response; +} */ + +/** + * @description Connect to OverKiz server. + * @param {Object} command - Command to send. + * @param {string} deviceURL - DeviceURL. + * @param {Object} data - Command data to send. + * @returns {Promise} Return Object of informations. + * @example + * overkiz.sendCommand(); + */ +async function sendCommand(command, deviceURL, data) { + logger.info(`Overkiz : Sending command...`); + + const payload = { + label: `${command} to device ${deviceURL}`, + actions: [ + { + deviceURL, + commands: [ + { + name: command, + parameters: [data], + }, + ], + }, + ], + }; + + const response = await this.overkizServerAPI.exec(payload); + const status = await response.wait(); + logger.debug(`Command sent: ${response.execId} - ${status}`); +} + +module.exports = { + sendCommand, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.setValue.js b/server/services/overkiz/lib/commands/overkiz.setValue.js new file mode 100644 index 0000000000..3953a2bbe9 --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.setValue.js @@ -0,0 +1,38 @@ +const logger = require('../../../../utils/logger'); +const { bindValue } = require('../utils/overkiz.bindValue'); +const { DEVICE_COMMANDS, DEVICE_STATES } = require('../utils/overkiz.constants'); +const { getNodeStateInfoByExternalId } = require('../utils/overkiz.externalId'); +const { sendCommand } = require('./overkiz.sendCommand'); + +/** + * @description Connect to OverKiz server. + * @param {Object} device - Device to set feature value. + * @param {Object} deviceFeature - Device feature to set value. + * @param {Object} value - Value to set. + * @example + * overkiz.setValue(); + */ +async function setValue(device, deviceFeature, value) { + const { deviceURL, state } = getNodeStateInfoByExternalId(deviceFeature); + const overkizValue = bindValue(device, deviceFeature, value); + + logger.info(`Setting value ${value} -> ${overkizValue} for device feature ${deviceFeature.external_id}`); + + switch (state) { + case DEVICE_STATES.HEATING_LEVEL_STATE: + sendCommand.bind(this)(DEVICE_COMMANDS.SET_HEATING_LEVEL, deviceURL, overkizValue); + break; + case DEVICE_STATES.COMFORT_TEMPERATURE_STATE: + sendCommand.bind(this)(DEVICE_COMMANDS.SET_COMFORT_TEMP, deviceURL, overkizValue); + break; + case DEVICE_STATES.ECO_TEMPERATURE_STATE: + sendCommand.bind(this)(DEVICE_COMMANDS.SET_ECO_TEMP, deviceURL, overkizValue); + break; + default: + // + } +} + +module.exports = { + setValue, +}; diff --git a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js new file mode 100644 index 0000000000..7d09c0abca --- /dev/null +++ b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js @@ -0,0 +1,64 @@ +const logger = require('../../../../utils/logger'); + +const { ServiceNotConfiguredError } = require('../../../../utils/coreErrors'); + +/** + * @description Update Gateway State. + * @param {Object} gateways - List of gateways. + * @example + * overkiz.updateGatewayState(); + */ +function updateGatewayState(gateways) { + logger.debug('UpdateGatwayState'); + + this.gateways = gateways; +} + +// eslint-disable-next-line jsdoc/require-returns +/** + * @description Update Devices State. + * @param {Object} devices - List of devices. + * @param {Object} rootPlace - Root place. + * @example + * overkiz.updateDevicesState(devices, rootPlace); + */ +function updateDevicesState(devices, rootPlace) { + logger.debug('UpdateDevicesState'); + + devices.forEach((device) => { + const placeObj = rootPlace.subPlaces.find((place) => place.oid === device.placeOID); + if (placeObj) { + device.place = placeObj.name; + } + this.devices[device.oid] = device; + delete this.devices[device.oid].api; + }); +} + +/** + * @description Synchronize Overkiz devices. + * @returns {Promise} Overkiz devices. + * @example + * overkiz.syncOverkizDevices(); + */ +async function syncOverkizDevices() { + if (!this.connected) { + throw new ServiceNotConfiguredError('OVERKIZ_NOT_CONNECTED'); + } + logger.debug(`Overkiz : Starting discovery`); + + this.scanInProgress = true; + + const setup = await this.overkizServerAPI.getSetup(); + updateGatewayState.call(this, setup.gateways[0]); + + const devices = await this.overkizServerAPI.getObjects(); + updateDevicesState.call(this, devices, setup.rootPlace); + + this.scanInProgress = false; +} + +module.exports = { + syncOverkizDevices, + updateDevicesState, +}; diff --git a/server/services/overkiz/lib/index.js b/server/services/overkiz/lib/index.js new file mode 100644 index 0000000000..dd451f3768 --- /dev/null +++ b/server/services/overkiz/lib/index.js @@ -0,0 +1,42 @@ +const Bottleneck = require('bottleneck/es5'); +const cron = require('node-cron'); + +const { getConfiguration, updateConfiguration } = require('./commands/overkiz.configuration'); +const { connect } = require('./commands/overkiz.connect'); +const { disconnect } = require('./commands/overkiz.disconnect'); +const { getDevicesStates } = require('./commands/overkiz.getDevicesStates'); +const { getOverkizDevices } = require('./commands/overkiz.getOverkizDevices'); +const { setValue } = require('./commands/overkiz.setValue'); +const { syncOverkizDevices } = require('./commands/overkiz.syncOverkizDevices'); + +// we rate-limit the number of request per seconds to poll lights +const pollLimiter = new Bottleneck({ + maxConcurrent: 1, + minTime: 100, // 100 ms +}); + +// we rate-limit the number of request per seconds to control lights +const setValueLimiter = new Bottleneck({ + minTime: 100, // 100 ms +}); + +const OverkizManager = function OverkizManager(gladys, serviceId) { + this.gladys = gladys; + this.serviceId = serviceId; + this.eventManager = gladys.event; + this.cron = cron; + this.devices = {}; + this.connected = false; + this.scanInProgress = false; +}; + +OverkizManager.prototype.connect = connect; +OverkizManager.prototype.disconnect = disconnect; +OverkizManager.prototype.syncOverkizDevices = syncOverkizDevices; +OverkizManager.prototype.getOverkizDevices = getOverkizDevices; +OverkizManager.prototype.poll = pollLimiter.wrap(getDevicesStates); +OverkizManager.prototype.setValue = setValueLimiter.wrap(setValue); +OverkizManager.prototype.getConfiguration = getConfiguration; +OverkizManager.prototype.updateConfiguration = updateConfiguration; + +module.exports = OverkizManager; diff --git a/server/services/overkiz/lib/utils/overkiz.bindValue.js b/server/services/overkiz/lib/utils/overkiz.bindValue.js new file mode 100644 index 0000000000..a8e4ce8436 --- /dev/null +++ b/server/services/overkiz/lib/utils/overkiz.bindValue.js @@ -0,0 +1,49 @@ +const { DEVICE_STATES, HEATING_MODES } = require('./overkiz.constants'); +const { getNodeStateInfoByExternalId } = require('./overkiz.externalId'); + +/** + * @description Bind value + * @param {Object} device - Device. + * @param {Object} deviceFeature - Device feature. + * @param {Object} value - Value to send. + * @returns {Object} Return the value adapted. + * @example + * const value = bindValue({}, {}}, 1); + */ +function bindValue(device, deviceFeature, value) { + const { state } = getNodeStateInfoByExternalId(deviceFeature); + if (state === DEVICE_STATES.OCCUPANCY_STATE) { + return value === 0 ? 'noPersonInside' : 'personInside'; + } + if (state === DEVICE_STATES.HEATING_LEVEL_STATE) { + return HEATING_MODES[value]; + } + if (state === DEVICE_STATES.COMFORT_TEMPERATURE_STATE || state === DEVICE_STATES.ECO_TEMPERATURE_STATE) { + return parseFloat(value); + } + return value; +} + +/** + * @description Unbind value + * @param {Object} device - Device. + * @param {string} stateName - Device state name. + * @param {string} stateValue - Device state value. + * @returns {Object} Return the value adapted. + * @example + * const value = unbindValue({}, 'name', 1); + */ +function unbindValue(device, stateName, stateValue) { + if (stateName === DEVICE_STATES.OCCUPANCY_STATE) { + return stateValue === 'noPersonInside' ? 0 : 1; + } + if (stateName === DEVICE_STATES.HEATING_LEVEL_STATE) { + return HEATING_MODES.indexOf(stateValue); + } + return stateValue; +} + +module.exports = { + bindValue, + unbindValue, +}; diff --git a/server/services/overkiz/lib/utils/overkiz.constants.js b/server/services/overkiz/lib/utils/overkiz.constants.js new file mode 100644 index 0000000000..0aa068edf9 --- /dev/null +++ b/server/services/overkiz/lib/utils/overkiz.constants.js @@ -0,0 +1,160 @@ +const DEVICE_PARAMS = { + FIRMWARE: 'FIRMWARE', + ONLINE: 'ONLINE', + STATE: 'STATE', +}; + +const SUPPORTED_SERVERS = { + atlantic_cozytouch: { + name: 'Atlantic Cozytouch', + host: 'ha110-1.overkiz.com', + endpoint: 'https://ha110-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Atlantic', + jwt: true, + configuration: { + COZYTOUCH_ATLANTIC_API: 'https://api.groupe-atlantic.com', + COZYTOUCH_CLIENT_ID: 'czduc0RZZXdWbjVGbVV4UmlYN1pVSUM3ZFI4YTphSDEzOXZmbzA1ZGdqeDJkSFVSQkFTbmhCRW9h', + }, + configuration_url: undefined, + }, + hi_kumo_asia: { + name: 'Hitachi Hi Kumo (Asia)', + host: 'ha203-1.overkiz.com', + endpoint: 'https://ha203-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Hitachi', + configuration_url: undefined, + }, + hi_kumo_europe: { + name: 'Hitachi Hi Kumo (Europe)', + host: 'ha117-1.overkiz.com', + endpoint: 'https://ha117-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Hitachi', + configuration_url: undefined, + }, + hi_kumo_oceania: { + name: 'Hitachi Hi Kumo (Oceania)', + host: 'ha203-1.overkiz.com', + endpoint: 'https://ha203-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Hitachi', + configuration_url: undefined, + }, + nexity: { + name: 'Nexity Eugénie', + host: 'ha106-1.overkiz.com', + endpoint: 'https://ha106-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Nexity', + configuration: { + NEXITY_API: 'https://api.egn.prd.aws-nexity.fr', + NEXITY_COGNITO_CLIENT_ID: '3mca95jd5ase5lfde65rerovok', + NEXITY_COGNITO_USER_POOL: 'eu-west-1_wj277ucoI', + NEXITY_COGNITO_REGION: 'eu-west-1', + }, + configuration_url: undefined, + }, + rexel: { + name: 'Rexel Energeasy Connect', + endpoint: 'https://ha112-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Rexel', + configuration_url: 'https://utilisateur.energeasyconnect.com/user/#/zone/equipements', + }, + somfy_europe: { + // uses https://ha101-1.overkiz.com + name: 'Somfy (Europe)', + endpoint: 'https://tahomalink.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Somfy', + configuration_url: 'https://www.tahomalink.com', + }, + somfy_america: { + name: 'Somfy (North America)', + endpoint: 'https://ha401-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Somfy', + configuration_url: undefined, + }, + somfy_oceania: { + name: 'Somfy (Oceania)', + endpoint: 'https://ha201-1.overkiz.com/enduser-mobile-web/enduserAPI/', + manufacturer: 'Somfy', + configuration_url: undefined, + }, +}; + +const OVERKIZ_API = { + GET_DEVICES: 'setup/devices', + GET_GATEWAYS: 'setup/gateways', + GET_HISTORY_EXECUTIONS: 'history/executions', + GET_DEVICE_DEFINITION: 'setup/devices/%', + GET_DEVICE_STATE: 'setup/devices/%/states', + REFRESH_DEVICES_STATE: 'setup/devices/states/refresh', // For device that supports refresh +}; + +const OVERKIZ_SERVER_PARAM = { + OVERKIZ_TYPE: 'OVERKIZ_TYPE', + OVERKIZ_SERVER_USERNAME: 'OVERKIZ_SERVER_USERNAME', + OVERKIZ_SERVER_PASSWORD: 'OVERKIZ_SERVER_PASSWORD', +}; + +const DEVICE_TYPES = { + SYSTEM: 1, + SENSOR: 2, +}; + +const DEVICE_UID_CLASSES = { + POD: 'Pod', + PROTOCOL_GATEWAY: 'ProtocolGateway', + HEATER: 'HeatingSystem', + TEMPERATURE: 'TemperatureSensor', + CONTACT: 'ContactSensor', + OCCUPANCY: 'OccupancySensor', + ELECTRICITY: 'ElectricitySensor', +}; + +const DEVICE_STATES = { + MODEL_STATE: 'io:ModelState', + POWER_STATE: 'io:PowerState', + MANUFACTURER_NAME_STATE: 'core:ManufacturerNameState', + FIRMWARE_REVISION_STATE: 'core:FirmwareRevision', + STATUS_STATE: 'core:StatusState', + AWAY_STATE: 'core:HolidaysModeState', + HEATING_LEVEL_STATE: 'io:TargetHeatingLevelState', + OCCUPANCY_STATE: 'core:OccupancyState', + TEMPERATURE_STATE: 'core:TemperatureState', + TARGET_TEMPERATURE_STATE: 'core:TargetTemperatureState', + COMFORT_TEMPERATURE_STATE: 'core:ComfortRoomTemperatureState', + ECO_TEMPERATURE_STATE: 'io:EffectiveTemperatureSetpointState', // 'core:EcoRoomTemperatureState', + ON_OFF_STATE: 'core:OnOffState', + ELECTRIC_ENERGY_CONSUMPTION_STATE: 'core:ElectricEnergyConsumptionState', + OPERATING_MODE_STATE: 'core:OperatingModeState', +}; + +const DEVICE_COMMANDS = { + SET_CURRENT_OPERATING_MODE: 'setCurrentOperatingMode', + SET_HEATING_LEVEL: 'setHeatingLevel', + SET_ECO_TEMP: 'setEcoTemperature', + SET_COMFORT_TEMP: 'setComfortTemperature', + SET_AWAY_MODE: 'setHolidays', + REFRESH_HEATING_LEVEL: 'refreshHeatingLevel', + REFRESH_ECO_TEMPERATURE: 'refreshEcoTemperature', + REFRESH_COMFORT_TEMPERATURE: 'refreshComfortTemperature', +}; + +const HEATING_MODES = ['off', 'frost-protection', 'eco', 'comfort-2', 'comfort-1', 'comfort']; + +const HEATING_STATES = { + STOPPED: 'standby', + BASIC: 'basic', + PROG: 'internal', // mode suivant un planing horaire + AUTO: 'auto', +}; + +module.exports = { + SUPPORTED_SERVERS, + OVERKIZ_SERVER_PARAM, + OVERKIZ_API, + DEVICE_PARAMS, + DEVICE_TYPES, + DEVICE_UID_CLASSES, + DEVICE_STATES, + DEVICE_COMMANDS, + HEATING_MODES, + HEATING_STATES, +}; diff --git a/server/services/overkiz/lib/utils/overkiz.externalId.js b/server/services/overkiz/lib/utils/overkiz.externalId.js new file mode 100644 index 0000000000..e2209415e7 --- /dev/null +++ b/server/services/overkiz/lib/utils/overkiz.externalId.js @@ -0,0 +1,72 @@ +/** + * @description Return name of device + * @param {Object} node - The zwave value. + * @returns {string} Return name. + * @example + * getDeviceName(node); + */ +function getDeviceName(node) { + return `${node.name} (${node.place})`; +} + +/** + * @description Return external id of device + * @param {Object} node - The zwave value. + * @returns {string} Return external id. + * @example + * getDeviceExternalId(node); + */ +function getDeviceExternalId(node) { + const deviceURL = node.URL; + return `overkiz:deviceURL:${deviceURL}`; +} + +/** + * @description Return external id of deviceFeature + * @param {Object} node - The node feature. + * @param {Object} state - The node state feature. + * @returns {string} Return external id. + * @example + * getDeviceFeatureExternalId(node); + */ +function getDeviceFeatureExternalId(node, state) { + const deviceURL = node.URL; + return `overkiz:deviceURL:${deviceURL}:state:${state}`; +} + +/** + * @description Return node info of device. + * @param {Object} device - The device. + * @returns {Object} Return all informations. + * @example + * getNodeInfoByExternalId({external_id: ''}); + */ +function getNodeInfoByExternalId(device) { + const array = device.external_id.split(':'); + return { + deviceURL: `${array[2]}:${array[3]}`, + }; +} + +/** + * @description Return node info of devicefeature. + * @param {Object} deviceFeature - The devicefeature. + * @returns {Object} Return all informations. + * @example + * getNodeStateInfoByExternalId({external_id: ''}); + */ +function getNodeStateInfoByExternalId(deviceFeature) { + const array = deviceFeature.external_id.split(':'); + return { + deviceURL: `${array[2]}:${array[3]}`, + state: `${array[5]}:${array[6]}`, + }; +} + +module.exports = { + getDeviceName, + getDeviceExternalId, + getDeviceFeatureExternalId, + getNodeInfoByExternalId, + getNodeStateInfoByExternalId, +}; diff --git a/server/services/overkiz/package-lock.json b/server/services/overkiz/package-lock.json new file mode 100644 index 0000000000..37468d4976 --- /dev/null +++ b/server/services/overkiz/package-lock.json @@ -0,0 +1,1014 @@ +{ + "name": "gladys-overkiz", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "gladys-overkiz", + "cpu": [ + "x64", + "arm", + "arm64" + ], + "os": [ + "darwin", + "linux", + "win32" + ], + "dependencies": { + "async-retry": "^1.3.3", + "axios": "^0.21.1", + "bluebird": "^3.7.0", + "bottleneck": "^2.19.5", + "node-cron": "^3.0.2", + "overkiz-api": "^2.0.1", + "sleep-promise": "^9.1.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/follow-redirects": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", + "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-cron": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz", + "integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==", + "dependencies": { + "uuid": "8.3.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/overkiz-api": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/overkiz-api/-/overkiz-api-2.0.1.tgz", + "integrity": "sha512-rMrHFO+dMY0/6XW6QoAYn9U2jDR54nQ7Oq/0SFu6JioU4aug5xkYcDb6itrKfzoD8elecaSidq1XMbQC3oIBVw==", + "dependencies": { + "request": "^2.88.2", + "request-promise": "^4.2.6" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", + "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", + "deprecated": "request-promise has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", + "dependencies": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dependencies": { + "lodash": "^4.17.19" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sleep-promise": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/sleep-promise/-/sleep-promise-9.1.0.tgz", + "integrity": "sha512-UHYzVpz9Xn8b+jikYSD6bqvf754xL2uBUzDFwiU6NcdZeifPr6UfgU43xpkPu67VMS88+TI2PSI7Eohgqf2fKA==" + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + } + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" + }, + "async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "requires": { + "retry": "0.13.1" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "requires": { + "follow-redirects": "^1.14.0" + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "follow-redirects": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", + "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "node-cron": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz", + "integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==", + "requires": { + "uuid": "8.3.2" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "overkiz-api": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/overkiz-api/-/overkiz-api-2.0.1.tgz", + "integrity": "sha512-rMrHFO+dMY0/6XW6QoAYn9U2jDR54nQ7Oq/0SFu6JioU4aug5xkYcDb6itrKfzoD8elecaSidq1XMbQC3oIBVw==", + "requires": { + "request": "^2.88.2", + "request-promise": "^4.2.6" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "request-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", + "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", + "requires": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "requires": { + "lodash": "^4.17.19" + } + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sleep-promise": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/sleep-promise/-/sleep-promise-9.1.0.tgz", + "integrity": "sha512-UHYzVpz9Xn8b+jikYSD6bqvf754xL2uBUzDFwiU6NcdZeifPr6UfgU43xpkPu67VMS88+TI2PSI7Eohgqf2fKA==" + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + } + } +} diff --git a/server/services/overkiz/package.json b/server/services/overkiz/package.json new file mode 100644 index 0000000000..e98835d952 --- /dev/null +++ b/server/services/overkiz/package.json @@ -0,0 +1,23 @@ +{ + "name": "gladys-overkiz", + "main": "index.js", + "os": [ + "darwin", + "linux", + "win32" + ], + "cpu": [ + "x64", + "arm", + "arm64" + ], + "scripts": {}, + "dependencies": { + "async-retry": "^1.3.3", + "axios": "^0.21.1", + "bluebird": "^3.7.0", + "bottleneck": "^2.19.5", + "node-cron": "^3.0.2", + "overkiz-api": "^2.0.1" + } +} From 0287cb3f0a91128aef007ffa24477f1a5b558ac4 Mon Sep 17 00:00:00 2001 From: POCHET Romuald Date: Sat, 13 May 2023 21:57:20 +0200 Subject: [PATCH 11/40] Merge --- .../integration/all/overkiz/OverkizDeviceBox.jsx | 4 +--- front/src/routes/integration/all/overkiz/actions.js | 12 ++++-------- .../all/overkiz/discover-page/EmptyState.jsx | 2 +- .../all/overkiz/settings-page/SettingsTab.jsx | 3 +-- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx index 2db85b00a5..3ee86f1f65 100644 --- a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx +++ b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx @@ -67,9 +67,7 @@ class OverkizDeviceBox extends Component {
- {firmware && ( -
{`Firmware: ${firmware}`}
- )} + {firmware &&
{`Firmware: ${firmware}`}
}
( +const EmptyState = ({}) => (
diff --git a/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx b/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx index ba45187b71..bb861e2f89 100644 --- a/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx +++ b/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx @@ -5,7 +5,6 @@ import cx from 'classnames'; import { RequestStatus } from '../../../../../utils/consts'; class SetupTab extends Component { - updateOverkizType = e => { this.props.updateConfiguration({ overkizType: e.target.value }); }; @@ -131,6 +130,6 @@ class SetupTab extends Component {
); } -}; +} export default SetupTab; From b8d7bf9f9fc60f15efc609aca732bb1a5c286dd6 Mon Sep 17 00:00:00 2001 From: POCHET Romuald Date: Sun, 14 May 2023 00:19:44 +0200 Subject: [PATCH 12/40] ES Lint --- front/src/components/boxs/device-in-room/DeviceRow.jsx | 3 --- .../components/boxs/device-in-room/EditDeviceInRoom.jsx | 2 +- front/src/routes/integration/all/overkiz/actions.js | 8 -------- .../routes/integration/all/overkiz/device-page/index.js | 4 +--- .../routes/integration/all/overkiz/discover-page/index.js | 4 +--- .../src/routes/integration/all/overkiz/edit-page/index.js | 3 +-- .../integration/all/overkiz/settings-page/SettingsTab.jsx | 4 ---- .../routes/integration/all/overkiz/settings-page/index.js | 7 +------ 8 files changed, 5 insertions(+), 30 deletions(-) diff --git a/front/src/components/boxs/device-in-room/DeviceRow.jsx b/front/src/components/boxs/device-in-room/DeviceRow.jsx index 3bf56f7802..9f7b25b2d3 100644 --- a/front/src/components/boxs/device-in-room/DeviceRow.jsx +++ b/front/src/components/boxs/device-in-room/DeviceRow.jsx @@ -9,11 +9,8 @@ import MultiLevelDeviceFeature from './device-features/MultiLevelDeviceFeature'; import NumberDeviceFeature from './device-features/NumberDeviceFeature'; import CoverDeviceFeature from './device-features/CoverDeviceFeature'; import ThermostatDeviceFeature from './device-features/ThermostatDeviceFeature'; -<<<<<<< HEAD import ThermostatModeDeviceFeature from './device-features/ThermostatModeDeviceFeature'; -======= import AirConditioningModeDeviceFeature from './device-features/AirConditioningModeDeviceFeature'; ->>>>>>> 93baf60bd1a494649413ef2e51d4d4c0f3d0750a const ROW_TYPE_BY_FEATURE_TYPE = { [DEVICE_FEATURE_TYPES.LIGHT.BINARY]: BinaryDeviceFeature, diff --git a/front/src/components/boxs/device-in-room/EditDeviceInRoom.jsx b/front/src/components/boxs/device-in-room/EditDeviceInRoom.jsx index 2d1a73045a..7dc620e0d6 100644 --- a/front/src/components/boxs/device-in-room/EditDeviceInRoom.jsx +++ b/front/src/components/boxs/device-in-room/EditDeviceInRoom.jsx @@ -20,7 +20,7 @@ const SUPPORTED_FEATURE_TYPES = [ DEVICE_FEATURE_TYPES.SHUTTER.POSITION, DEVICE_FEATURE_TYPES.SHUTTER.STATE, DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE, - DEVICE_FEATURE_TYPES.THERMOSTAT.MODE + DEVICE_FEATURE_TYPES.THERMOSTAT.MODE, DEVICE_FEATURE_TYPES.AIR_CONDITIONING.MODE, DEVICE_FEATURE_TYPES.AIR_CONDITIONING.TARGET_TEMPERATURE ]; diff --git a/front/src/routes/integration/all/overkiz/actions.js b/front/src/routes/integration/all/overkiz/actions.js index 5d697944ad..45ee381a3b 100644 --- a/front/src/routes/integration/all/overkiz/actions.js +++ b/front/src/routes/integration/all/overkiz/actions.js @@ -50,24 +50,16 @@ function createActions(store) { saveConfigurationStatus: RequestStatus.Getting }); -<<<<<<< HEAD - const { overkizType, overkizUsername, overkizPassword } = state; -======= const { overkizType, overkizUsername, overkizPassword, } = state; ->>>>>>> 93baf60bd1a494649413ef2e51d4d4c0f3d0750a try { await state.httpClient.post(`/api/v1/service/overkiz/configuration`, { overkizType, overkizUsername, -<<<<<<< HEAD - overkizPassword -======= overkizPassword, ->>>>>>> 93baf60bd1a494649413ef2e51d4d4c0f3d0750a }); store.setState({ diff --git a/front/src/routes/integration/all/overkiz/device-page/index.js b/front/src/routes/integration/all/overkiz/device-page/index.js index b13f2f4b18..a80f10e678 100644 --- a/front/src/routes/integration/all/overkiz/device-page/index.js +++ b/front/src/routes/integration/all/overkiz/device-page/index.js @@ -1,10 +1,8 @@ import { Component } from 'preact'; import { connect } from 'unistore/preact'; -import actions from '../actions'; import OverkizPage from '../OverkizPage'; import DeviceTab from './DeviceTab'; -@connect('user,overkizDevices,housesWithRooms,getOverkizStatus', actions) class OverkizIntegration extends Component { componentWillMount() { this.props.getOverkizDevices(); @@ -21,4 +19,4 @@ class OverkizIntegration extends Component { } } -export default OverkizIntegration; +export default connect('user,overkizDevices,housesWithRooms,getOverkizStatus', {})(OverkizIntegration); diff --git a/front/src/routes/integration/all/overkiz/discover-page/index.js b/front/src/routes/integration/all/overkiz/discover-page/index.js index 4f8dbddb8e..6629be7b68 100644 --- a/front/src/routes/integration/all/overkiz/discover-page/index.js +++ b/front/src/routes/integration/all/overkiz/discover-page/index.js @@ -1,10 +1,8 @@ import { Component } from 'preact'; import { connect } from 'unistore/preact'; -import actions from '../actions'; import OverkizPage from '../OverkizPage'; import DiscoverTab from './DiscoverTab'; -@connect('user,session,httpClient,housesWithRooms,discoveredDevices,loading,errorLoading', actions) class OverkizIntegration extends Component { async componentWillMount() { this.props.getDiscoveredOverkizDevices(); @@ -21,4 +19,4 @@ class OverkizIntegration extends Component { } } -export default OverkizIntegration; +export default connect('user,session,httpClient,housesWithRooms,discoveredDevices,loading,errorLoading', {})(OverkizIntegration); diff --git a/front/src/routes/integration/all/overkiz/edit-page/index.js b/front/src/routes/integration/all/overkiz/edit-page/index.js index 13fff479f7..0075164190 100644 --- a/front/src/routes/integration/all/overkiz/edit-page/index.js +++ b/front/src/routes/integration/all/overkiz/edit-page/index.js @@ -3,7 +3,6 @@ import { connect } from 'unistore/preact'; import OverkizPage from '../OverkizPage'; import UpdateDevice from '../../../../../components/device'; -@connect('user,session,httpClient,currentIntegration,houses', {}) class EditOverkizDevice extends Component { render(props, {}) { return ( @@ -19,4 +18,4 @@ class EditOverkizDevice extends Component { } } -export default EditOverkizDevice; +export default connect('user,session,httpClient,currentIntegration,houses', {})(EditOverkizDevice); diff --git a/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx b/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx index f5103af76c..102899e301 100644 --- a/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx +++ b/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx @@ -131,10 +131,6 @@ class SetupTab extends Component {
); } -<<<<<<< HEAD -} -======= }; ->>>>>>> 93baf60bd1a494649413ef2e51d4d4c0f3d0750a export default SetupTab; diff --git a/front/src/routes/integration/all/overkiz/settings-page/index.js b/front/src/routes/integration/all/overkiz/settings-page/index.js index c8c3a1233a..51bf042ca8 100644 --- a/front/src/routes/integration/all/overkiz/settings-page/index.js +++ b/front/src/routes/integration/all/overkiz/settings-page/index.js @@ -1,15 +1,10 @@ import { Component } from 'preact'; import { connect } from 'unistore/preact'; -import actions from '../actions'; import OverkizPage from '../OverkizPage'; import SettingsTab from './SettingsTab'; import { SUPPORTED_SERVERS } from '../../../../../../../server/services/overkiz/lib/utils/overkiz.constants'; import { WEBSOCKET_MESSAGE_TYPES } from '../../../../../../../server/utils/constants'; -@connect( - 'user,session,overkizType,overkizUsername,overkizPassword,overkizGetConfigurationStatus,saveConfigurationStatus', - actions -) class OverkizSettingsTab extends Component { componentWillMount() { this.props.getIntegrationByName('overkiz'); @@ -39,4 +34,4 @@ class OverkizSettingsTab extends Component { } } -export default OverkizSettingsTab; +export default connect('user,session,overkizType,overkizUsername,overkizPassword,overkizGetConfigurationStatus,saveConfigurationStatus', {})(OverkizSettingsTab); \ No newline at end of file From 0ff1524cd114f9d698c79d52932a492c0599ff1f Mon Sep 17 00:00:00 2001 From: POCHET Romuald Date: Sun, 14 May 2023 00:40:56 +0200 Subject: [PATCH 13/40] ES Lint --- .../components/boxs/device-in-room/DeviceRow.jsx | 5 +---- .../routes/integration/all/overkiz/actions.js | 8 ++------ .../all/overkiz/discover-page/EmptyState.jsx | 1 - .../all/overkiz/discover-page/index.js | 5 ++++- .../all/overkiz/settings-page/SettingsTab.jsx | 3 +-- .../all/overkiz/settings-page/index.js | 5 ++++- .../lib/commands/overkiz.configuration.js | 2 +- .../overkiz/lib/commands/overkiz.connect.js | 2 +- .../overkiz/lib/commands/overkiz.disconnect.js | 2 +- .../lib/commands/overkiz.getDevicesStates.js | 4 ++-- .../overkiz/lib/commands/overkiz.sendCommand.js | 10 +++++----- .../overkiz/lib/commands/overkiz.setValue.js | 6 +++--- .../lib/commands/overkiz.syncOverkizDevices.js | 6 +++--- .../overkiz/lib/utils/overkiz.bindValue.js | 12 ++++++------ .../overkiz/lib/utils/overkiz.externalId.js | 16 ++++++++-------- 15 files changed, 42 insertions(+), 45 deletions(-) diff --git a/front/src/components/boxs/device-in-room/DeviceRow.jsx b/front/src/components/boxs/device-in-room/DeviceRow.jsx index 3d0bfda459..9cfb0b4bdd 100644 --- a/front/src/components/boxs/device-in-room/DeviceRow.jsx +++ b/front/src/components/boxs/device-in-room/DeviceRow.jsx @@ -25,12 +25,9 @@ const ROW_TYPE_BY_FEATURE_TYPE = { [DEVICE_FEATURE_TYPES.CURTAIN.STATE]: CoverDeviceFeature, [DEVICE_FEATURE_TYPES.CURTAIN.POSITION]: MultiLevelDeviceFeature, [DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE]: ThermostatDeviceFeature, -<<<<<<< HEAD - [DEVICE_FEATURE_TYPES.THERMOSTAT.MODE]: ThermostatModeDeviceFeature -======= + [DEVICE_FEATURE_TYPES.THERMOSTAT.MODE]: ThermostatModeDeviceFeature, [DEVICE_FEATURE_TYPES.AIR_CONDITIONING.MODE]: AirConditioningModeDeviceFeature, [DEVICE_FEATURE_TYPES.AIR_CONDITIONING.TARGET_TEMPERATURE]: ThermostatDeviceFeature ->>>>>>> 93baf60bd1a494649413ef2e51d4d4c0f3d0750a }; const DeviceRow = ({ children, ...props }) => { diff --git a/front/src/routes/integration/all/overkiz/actions.js b/front/src/routes/integration/all/overkiz/actions.js index 45ee381a3b..71d9ac7b9e 100644 --- a/front/src/routes/integration/all/overkiz/actions.js +++ b/front/src/routes/integration/all/overkiz/actions.js @@ -50,16 +50,12 @@ function createActions(store) { saveConfigurationStatus: RequestStatus.Getting }); - const { - overkizType, - overkizUsername, - overkizPassword, - } = state; + const { overkizType, overkizUsername, overkizPassword } = state; try { await state.httpClient.post(`/api/v1/service/overkiz/configuration`, { overkizType, overkizUsername, - overkizPassword, + overkizPassword }); store.setState({ diff --git a/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx b/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx index 36fd99e314..10a7b49137 100644 --- a/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx +++ b/front/src/routes/integration/all/overkiz/discover-page/EmptyState.jsx @@ -3,7 +3,6 @@ import cx from 'classnames'; import style from './style.css'; const EmptyState = ({}) => ( -
diff --git a/front/src/routes/integration/all/overkiz/discover-page/index.js b/front/src/routes/integration/all/overkiz/discover-page/index.js index 6629be7b68..40870d54f8 100644 --- a/front/src/routes/integration/all/overkiz/discover-page/index.js +++ b/front/src/routes/integration/all/overkiz/discover-page/index.js @@ -19,4 +19,7 @@ class OverkizIntegration extends Component { } } -export default connect('user,session,httpClient,housesWithRooms,discoveredDevices,loading,errorLoading', {})(OverkizIntegration); +export default connect( + 'user,session,httpClient,housesWithRooms,discoveredDevices,loading,errorLoading', + {} +)(OverkizIntegration); diff --git a/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx b/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx index 102899e301..bb861e2f89 100644 --- a/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx +++ b/front/src/routes/integration/all/overkiz/settings-page/SettingsTab.jsx @@ -5,7 +5,6 @@ import cx from 'classnames'; import { RequestStatus } from '../../../../../utils/consts'; class SetupTab extends Component { - updateOverkizType = e => { this.props.updateConfiguration({ overkizType: e.target.value }); }; @@ -131,6 +130,6 @@ class SetupTab extends Component {
); } -}; +} export default SetupTab; diff --git a/front/src/routes/integration/all/overkiz/settings-page/index.js b/front/src/routes/integration/all/overkiz/settings-page/index.js index 51bf042ca8..b7dffb4d56 100644 --- a/front/src/routes/integration/all/overkiz/settings-page/index.js +++ b/front/src/routes/integration/all/overkiz/settings-page/index.js @@ -34,4 +34,7 @@ class OverkizSettingsTab extends Component { } } -export default connect('user,session,overkizType,overkizUsername,overkizPassword,overkizGetConfigurationStatus,saveConfigurationStatus', {})(OverkizSettingsTab); \ No newline at end of file +export default connect( + 'user,session,overkizType,overkizUsername,overkizPassword,overkizGetConfigurationStatus,saveConfigurationStatus', + {} +)(OverkizSettingsTab); diff --git a/server/services/overkiz/lib/commands/overkiz.configuration.js b/server/services/overkiz/lib/commands/overkiz.configuration.js index fac891af73..e979d76b87 100644 --- a/server/services/overkiz/lib/commands/overkiz.configuration.js +++ b/server/services/overkiz/lib/commands/overkiz.configuration.js @@ -3,7 +3,7 @@ const { OVERKIZ_SERVER_PARAM } = require('../utils/overkiz.constants'); /** * @description Get Overkiz configuration. - * @returns {Promise} Return Overkiz configuration. + * @returns {Promise} Return Overkiz configuration. * @example * overkiz.getConfiguration(); */ diff --git a/server/services/overkiz/lib/commands/overkiz.connect.js b/server/services/overkiz/lib/commands/overkiz.connect.js index 7ae220ed23..56171eeb09 100644 --- a/server/services/overkiz/lib/commands/overkiz.connect.js +++ b/server/services/overkiz/lib/commands/overkiz.connect.js @@ -6,7 +6,7 @@ const { OVERKIZ_SERVER_PARAM, SUPPORTED_SERVERS } = require('../utils/overkiz.co /** * @description Connect to OverKiz server. - * @returns {Promise} Return Object of informations. + * @returns {Promise} Return Object of informations. * @example * overkiz.connect(); */ diff --git a/server/services/overkiz/lib/commands/overkiz.disconnect.js b/server/services/overkiz/lib/commands/overkiz.disconnect.js index f9c2c7b050..cb44932763 100644 --- a/server/services/overkiz/lib/commands/overkiz.disconnect.js +++ b/server/services/overkiz/lib/commands/overkiz.disconnect.js @@ -2,7 +2,7 @@ const logger = require('../../../../utils/logger'); /** * @description Disconnect to OverKiz server. - * @returns {Promise} Return Object of informations. + * @returns {Promise} Return Object of informations. * @example * overkiz.disconnect(); */ diff --git a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js index 9475e10067..d5d19841cc 100644 --- a/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js +++ b/server/services/overkiz/lib/commands/overkiz.getDevicesStates.js @@ -5,8 +5,8 @@ const { EVENTS, DEVICE_FEATURE_CATEGORIES } = require('../../../../utils/constan /** * @description Update device states. - * @param {Object} device - Deviceto update states. - * @returns {Promise} Return Object of informations. + * @param {object} device - Deviceto update states. + * @returns {Promise} Return Object of informations. * @example * overkiz.getDevicesStates(); */ diff --git a/server/services/overkiz/lib/commands/overkiz.sendCommand.js b/server/services/overkiz/lib/commands/overkiz.sendCommand.js index 24d1404044..840c35da90 100644 --- a/server/services/overkiz/lib/commands/overkiz.sendCommand.js +++ b/server/services/overkiz/lib/commands/overkiz.sendCommand.js @@ -2,7 +2,7 @@ const logger = require('../../../../utils/logger'); /** * @description Connect to OverKiz server. - * @returns {Promise} Return state of Execution. + * @returns {Promise} Return state of Execution. * @example * overkiz.getExecutionStates(); */ @@ -41,7 +41,7 @@ const logger = require('../../../../utils/logger'); /** * @description Connect to OverKiz server. * @param {string} execId - Execution Id. - * @returns {Promise} Return state of Execution. + * @returns {Promise} Return state of Execution. * @example * overkiz.getExecutionState('01234'); */ @@ -79,10 +79,10 @@ const logger = require('../../../../utils/logger'); /** * @description Connect to OverKiz server. - * @param {Object} command - Command to send. + * @param {object} command - Command to send. * @param {string} deviceURL - DeviceURL. - * @param {Object} data - Command data to send. - * @returns {Promise} Return Object of informations. + * @param {object} data - Command data to send. + * @returns {Promise} Return object of informations. * @example * overkiz.sendCommand(); */ diff --git a/server/services/overkiz/lib/commands/overkiz.setValue.js b/server/services/overkiz/lib/commands/overkiz.setValue.js index 3953a2bbe9..c60f342a07 100644 --- a/server/services/overkiz/lib/commands/overkiz.setValue.js +++ b/server/services/overkiz/lib/commands/overkiz.setValue.js @@ -6,9 +6,9 @@ const { sendCommand } = require('./overkiz.sendCommand'); /** * @description Connect to OverKiz server. - * @param {Object} device - Device to set feature value. - * @param {Object} deviceFeature - Device feature to set value. - * @param {Object} value - Value to set. + * @param {object} device - Device to set feature value. + * @param {object} deviceFeature - Device feature to set value. + * @param {object} value - Value to set. * @example * overkiz.setValue(); */ diff --git a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js index 7d09c0abca..dc72b1f272 100644 --- a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js +++ b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js @@ -4,7 +4,7 @@ const { ServiceNotConfiguredError } = require('../../../../utils/coreErrors'); /** * @description Update Gateway State. - * @param {Object} gateways - List of gateways. + * @param {object} gateways - List of gateways. * @example * overkiz.updateGatewayState(); */ @@ -17,8 +17,8 @@ function updateGatewayState(gateways) { // eslint-disable-next-line jsdoc/require-returns /** * @description Update Devices State. - * @param {Object} devices - List of devices. - * @param {Object} rootPlace - Root place. + * @param {object} devices - List of devices. + * @param {object} rootPlace - Root place. * @example * overkiz.updateDevicesState(devices, rootPlace); */ diff --git a/server/services/overkiz/lib/utils/overkiz.bindValue.js b/server/services/overkiz/lib/utils/overkiz.bindValue.js index a8e4ce8436..f1ea84c34b 100644 --- a/server/services/overkiz/lib/utils/overkiz.bindValue.js +++ b/server/services/overkiz/lib/utils/overkiz.bindValue.js @@ -3,10 +3,10 @@ const { getNodeStateInfoByExternalId } = require('./overkiz.externalId'); /** * @description Bind value - * @param {Object} device - Device. - * @param {Object} deviceFeature - Device feature. - * @param {Object} value - Value to send. - * @returns {Object} Return the value adapted. + * @param {object} device - Device. + * @param {object} deviceFeature - Device feature. + * @param {object} value - Value to send. + * @returns {object} Return the value adapted. * @example * const value = bindValue({}, {}}, 1); */ @@ -26,10 +26,10 @@ function bindValue(device, deviceFeature, value) { /** * @description Unbind value - * @param {Object} device - Device. + * @param {object} device - Device. * @param {string} stateName - Device state name. * @param {string} stateValue - Device state value. - * @returns {Object} Return the value adapted. + * @returns {object} Return the value adapted. * @example * const value = unbindValue({}, 'name', 1); */ diff --git a/server/services/overkiz/lib/utils/overkiz.externalId.js b/server/services/overkiz/lib/utils/overkiz.externalId.js index e2209415e7..e8f3874804 100644 --- a/server/services/overkiz/lib/utils/overkiz.externalId.js +++ b/server/services/overkiz/lib/utils/overkiz.externalId.js @@ -1,6 +1,6 @@ /** * @description Return name of device - * @param {Object} node - The zwave value. + * @param {object} node - The zwave value. * @returns {string} Return name. * @example * getDeviceName(node); @@ -11,7 +11,7 @@ function getDeviceName(node) { /** * @description Return external id of device - * @param {Object} node - The zwave value. + * @param {object} node - The zwave value. * @returns {string} Return external id. * @example * getDeviceExternalId(node); @@ -23,8 +23,8 @@ function getDeviceExternalId(node) { /** * @description Return external id of deviceFeature - * @param {Object} node - The node feature. - * @param {Object} state - The node state feature. + * @param {object} node - The node feature. + * @param {object} state - The node state feature. * @returns {string} Return external id. * @example * getDeviceFeatureExternalId(node); @@ -36,8 +36,8 @@ function getDeviceFeatureExternalId(node, state) { /** * @description Return node info of device. - * @param {Object} device - The device. - * @returns {Object} Return all informations. + * @param {object} device - The device. + * @returns {object} Return all informations. * @example * getNodeInfoByExternalId({external_id: ''}); */ @@ -50,8 +50,8 @@ function getNodeInfoByExternalId(device) { /** * @description Return node info of devicefeature. - * @param {Object} deviceFeature - The devicefeature. - * @returns {Object} Return all informations. + * @param {object} deviceFeature - The devicefeature. + * @returns {object} Return all informations. * @example * getNodeStateInfoByExternalId({external_id: ''}); */ From 54102feb8406cdb702b3df9e63256cd21580d777 Mon Sep 17 00:00:00 2001 From: POCHET Romuald Date: Wed, 24 May 2023 12:41:27 +0200 Subject: [PATCH 14/40] Merge --- server/services/overkiz/index.js | 4 ++-- .../overkiz/lib/commands/overkiz.configuration.js | 2 +- .../lib/commands/overkiz.syncOverkizDevices.js | 2 +- .../services/overkiz/lib/utils/overkiz.bindValue.js | 4 ++-- .../overkiz/lib/utils/overkiz.externalId.js | 6 +++--- server/services/overkiz/package-lock.json | 13 +------------ 6 files changed, 10 insertions(+), 21 deletions(-) diff --git a/server/services/overkiz/index.js b/server/services/overkiz/index.js index 5771e874d3..94b7fc453f 100644 --- a/server/services/overkiz/index.js +++ b/server/services/overkiz/index.js @@ -9,7 +9,7 @@ module.exports = function OverkizService(gladys, serviceId) { /** * @public - * @description This function starts the Overkiz service + * @description This function starts the Overkiz service. * @example * gladys.services.overkiz.start(); */ @@ -32,7 +32,7 @@ module.exports = function OverkizService(gladys, serviceId) { /** * @public - * @description This function stops the Overkiz service + * @description This function stops the Overkiz service. * @example * gladys.services.overkiz.stop(); */ diff --git a/server/services/overkiz/lib/commands/overkiz.configuration.js b/server/services/overkiz/lib/commands/overkiz.configuration.js index e979d76b87..168bde832e 100644 --- a/server/services/overkiz/lib/commands/overkiz.configuration.js +++ b/server/services/overkiz/lib/commands/overkiz.configuration.js @@ -28,7 +28,7 @@ async function getConfiguration() { /** * @description Update Overkiz configuration. - * @param {Object} configuration - The Overkiz configuration. + * @param {object} configuration - The Overkiz configuration. * @example * overkiz.updateConfiguration(); */ diff --git a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js index dc72b1f272..52c5cdd526 100644 --- a/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js +++ b/server/services/overkiz/lib/commands/overkiz.syncOverkizDevices.js @@ -37,7 +37,7 @@ function updateDevicesState(devices, rootPlace) { /** * @description Synchronize Overkiz devices. - * @returns {Promise} Overkiz devices. + * @returns {Promise} Overkiz devices. * @example * overkiz.syncOverkizDevices(); */ diff --git a/server/services/overkiz/lib/utils/overkiz.bindValue.js b/server/services/overkiz/lib/utils/overkiz.bindValue.js index f1ea84c34b..635536c1c0 100644 --- a/server/services/overkiz/lib/utils/overkiz.bindValue.js +++ b/server/services/overkiz/lib/utils/overkiz.bindValue.js @@ -2,7 +2,7 @@ const { DEVICE_STATES, HEATING_MODES } = require('./overkiz.constants'); const { getNodeStateInfoByExternalId } = require('./overkiz.externalId'); /** - * @description Bind value + * @description Bind value. * @param {object} device - Device. * @param {object} deviceFeature - Device feature. * @param {object} value - Value to send. @@ -25,7 +25,7 @@ function bindValue(device, deviceFeature, value) { } /** - * @description Unbind value + * @description Unbind value. * @param {object} device - Device. * @param {string} stateName - Device state name. * @param {string} stateValue - Device state value. diff --git a/server/services/overkiz/lib/utils/overkiz.externalId.js b/server/services/overkiz/lib/utils/overkiz.externalId.js index e8f3874804..529e2c1b84 100644 --- a/server/services/overkiz/lib/utils/overkiz.externalId.js +++ b/server/services/overkiz/lib/utils/overkiz.externalId.js @@ -1,5 +1,5 @@ /** - * @description Return name of device + * @description Return name of device. * @param {object} node - The zwave value. * @returns {string} Return name. * @example @@ -10,7 +10,7 @@ function getDeviceName(node) { } /** - * @description Return external id of device + * @description Return external id of device. * @param {object} node - The zwave value. * @returns {string} Return external id. * @example @@ -22,7 +22,7 @@ function getDeviceExternalId(node) { } /** - * @description Return external id of deviceFeature + * @description Return external id of deviceFeature. * @param {object} node - The node feature. * @param {object} state - The node state feature. * @returns {string} Return external id. diff --git a/server/services/overkiz/package-lock.json b/server/services/overkiz/package-lock.json index 37468d4976..1d06d0e7ff 100644 --- a/server/services/overkiz/package-lock.json +++ b/server/services/overkiz/package-lock.json @@ -21,8 +21,7 @@ "bluebird": "^3.7.0", "bottleneck": "^2.19.5", "node-cron": "^3.0.2", - "overkiz-api": "^2.0.1", - "sleep-promise": "^9.1.0" + "overkiz-api": "^2.0.1" } }, "node_modules/ajv": { @@ -489,11 +488,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/sleep-promise": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/sleep-promise/-/sleep-promise-9.1.0.tgz", - "integrity": "sha512-UHYzVpz9Xn8b+jikYSD6bqvf754xL2uBUzDFwiU6NcdZeifPr6UfgU43xpkPu67VMS88+TI2PSI7Eohgqf2fKA==" - }, "node_modules/sshpk": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", @@ -939,11 +933,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "sleep-promise": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/sleep-promise/-/sleep-promise-9.1.0.tgz", - "integrity": "sha512-UHYzVpz9Xn8b+jikYSD6bqvf754xL2uBUzDFwiU6NcdZeifPr6UfgU43xpkPu67VMS88+TI2PSI7Eohgqf2fKA==" - }, "sshpk": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", From 0c0109b8fe75e79a308f695d820a3d665d25cdb8 Mon Sep 17 00:00:00 2001 From: POCHET Romuald Date: Sat, 27 May 2023 22:38:41 +0200 Subject: [PATCH 15/40] Refactor connect --- front/src/routes/integration/all/overkiz/device-page/index.js | 3 ++- .../src/routes/integration/all/overkiz/discover-page/index.js | 3 ++- .../src/routes/integration/all/overkiz/settings-page/index.js | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/front/src/routes/integration/all/overkiz/device-page/index.js b/front/src/routes/integration/all/overkiz/device-page/index.js index a80f10e678..17c92bb06c 100644 --- a/front/src/routes/integration/all/overkiz/device-page/index.js +++ b/front/src/routes/integration/all/overkiz/device-page/index.js @@ -1,5 +1,6 @@ import { Component } from 'preact'; import { connect } from 'unistore/preact'; +import actions from '../actions'; import OverkizPage from '../OverkizPage'; import DeviceTab from './DeviceTab'; @@ -19,4 +20,4 @@ class OverkizIntegration extends Component { } } -export default connect('user,overkizDevices,housesWithRooms,getOverkizStatus', {})(OverkizIntegration); +export default connect('user,overkizDevices,housesWithRooms,getOverkizStatus', actions)(OverkizIntegration); diff --git a/front/src/routes/integration/all/overkiz/discover-page/index.js b/front/src/routes/integration/all/overkiz/discover-page/index.js index 40870d54f8..0563d2edea 100644 --- a/front/src/routes/integration/all/overkiz/discover-page/index.js +++ b/front/src/routes/integration/all/overkiz/discover-page/index.js @@ -1,5 +1,6 @@ import { Component } from 'preact'; import { connect } from 'unistore/preact'; +import actions from '../actions'; import OverkizPage from '../OverkizPage'; import DiscoverTab from './DiscoverTab'; @@ -21,5 +22,5 @@ class OverkizIntegration extends Component { export default connect( 'user,session,httpClient,housesWithRooms,discoveredDevices,loading,errorLoading', - {} + actions )(OverkizIntegration); diff --git a/front/src/routes/integration/all/overkiz/settings-page/index.js b/front/src/routes/integration/all/overkiz/settings-page/index.js index b7dffb4d56..25d9194b4b 100644 --- a/front/src/routes/integration/all/overkiz/settings-page/index.js +++ b/front/src/routes/integration/all/overkiz/settings-page/index.js @@ -1,5 +1,6 @@ import { Component } from 'preact'; import { connect } from 'unistore/preact'; +import actions from '../actions'; import OverkizPage from '../OverkizPage'; import SettingsTab from './SettingsTab'; import { SUPPORTED_SERVERS } from '../../../../../../../server/services/overkiz/lib/utils/overkiz.constants'; @@ -36,5 +37,5 @@ class OverkizSettingsTab extends Component { export default connect( 'user,session,overkizType,overkizUsername,overkizPassword,overkizGetConfigurationStatus,saveConfigurationStatus', - {} + actions )(OverkizSettingsTab); From ad8cdf45f6f44d8e9efb38f0c1d5a8121bdd06d1 Mon Sep 17 00:00:00 2001 From: POCHET Romuald Date: Fri, 23 Jun 2023 13:03:25 +0200 Subject: [PATCH 16/40] New API --- front/src/config/i18n/en.json | 16 ++--- front/src/config/i18n/fr.json | 4 +- .../all/overkiz/OverkizDeviceBox.jsx | 16 ++++- .../routes/integration/all/overkiz/actions.js | 30 ++++++--- .../all/overkiz/settings-page/SettingsTab.jsx | 65 +++++++++++-------- .../all/overkiz/settings-page/index.js | 4 +- .../overkiz/api/overkiz.controller.js | 20 +++++- server/services/overkiz/index.js | 2 +- .../overkiz/lib/client/overkiz.api.js | 64 ++++++++++++++++++ .../overkiz/lib/client/overkiz.cozytouch.js | 57 ++++++++++++++++ .../overkiz/lib/client/overkiz.default.js | 22 +++++++ .../lib/commands/overkiz.configuration.js | 2 +- .../overkiz/lib/commands/overkiz.connect.js | 12 ++-- .../lib/commands/overkiz.getOverkizDevices.js | 24 +++---- .../lib/commands/overkiz.sendCommand.js | 25 ++++--- .../overkiz/lib/commands/overkiz.setValue.js | 2 +- .../commands/overkiz.syncOverkizDevices.js | 8 +-- .../lib/{utils => }/overkiz.constants.js | 24 +++---- .../overkiz/lib/utils/overkiz.bindValue.js | 2 +- .../overkiz/lib/utils/overkiz.externalId.js | 8 +-- server/services/overkiz/package.json | 3 +- 21 files changed, 298 insertions(+), 112 deletions(-) create mode 100644 server/services/overkiz/lib/client/overkiz.api.js create mode 100644 server/services/overkiz/lib/client/overkiz.cozytouch.js create mode 100644 server/services/overkiz/lib/client/overkiz.default.js rename server/services/overkiz/lib/{utils => }/overkiz.constants.js (92%) diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index d1eb9766e5..e9b9febb49 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -1202,13 +1202,14 @@ "documentation": "Overkiz documentation", "device": { "title": "", - "search": "", - "noDeviceFound": "", - "nameLabel": "", - "namePlaceholder": "", - "modelLabel": "", - "roomLabel": "", - "featuresLabel": "", + "search": "Search", + "noDeviceFound": "No Overkiz device found", + "nameLabel": "Name", + "namePlaceholder": "Enter device name", + "modelLabel": "Model", + "stateLabel": "Programmation", + "roomLabel": "room", + "featuresLabel": "Features", "createButton": "Save", "updateButton": "Update", "deleteButton": "Delete", @@ -1233,7 +1234,6 @@ "userPlaceholder": "Enter Overkiz username", "passwordLabel": "Password", "passwordPlaceholder": "Enter Overkiz password", - "connectButton": "Connection", "error": "An error occured while saving configuration.", "connecting": "Configuration saved. Now connecting to your Overkiz cloud account...", "connected": "Connected to the Overkiz cloud account with success !", diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index 9e6068d771..94a564ea3b 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -1207,6 +1207,7 @@ "nameLabel": "Nom de l'appareil", "namePlaceholder": "Entrez le nom de votre appareil", "modelLabel": "Modèle", + "stateLabel": "Programme", "roomLabel": "Pièce", "createButton": "Sauvegarder", "updateButton": "Mettre à jour", @@ -1236,8 +1237,7 @@ "userLabel": "Nom d'utilisateur", "userPlaceholder": "Entrez le nom d'utilisateur Overkiz", "passwordLabel": "Mot de passe", - "passwordPlaceholder": "Entrez le mot de passe utilisateur Overkiz", - "connectButton": "Connexion" + "passwordPlaceholder": "Entrez le mot de passe utilisateur Overkiz" }, "error": { "defaultError": "Une erreur s'est produite lors de l'enregistrement de l'appareil.", diff --git a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx index 3ee86f1f65..c909a8d576 100644 --- a/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx +++ b/front/src/routes/integration/all/overkiz/OverkizDeviceBox.jsx @@ -2,7 +2,7 @@ import { Component } from 'preact'; import { Text, Localizer } from 'preact-i18n'; import cx from 'classnames'; import { DeviceFeatureCategoriesIcon } from '../../../../utils/consts'; -import { DEVICE_PARAMS } from '../../../../../../server/services/overkiz/lib/utils/overkiz.constants'; +import { DEVICE_PARAMS } from '../../../../../../server/services/overkiz/lib/overkiz.constants'; import get from 'get-value'; class OverkizDeviceBox extends Component { @@ -55,6 +55,7 @@ class OverkizDeviceBox extends Component { render({ deviceIndex, device, housesWithRooms, editable, ...props }, { loading, errorMessage }) { const online = device.params.find(param => param.name === DEVICE_PARAMS.ONLINE).value === '1'; const firmware = device.params.find(param => param.name === DEVICE_PARAMS.FIRMWARE).value; + const state = device.params.find(param => param.name === DEVICE_PARAMS.STATE).value; return (
@@ -113,6 +114,19 @@ class OverkizDeviceBox extends Component { />
+
+ + +
+ {editable && (