├── manage
├── easyui
│ └── themes
│ │ ├── default
│ │ ├── numberbox.css
│ │ ├── images
│ │ │ ├── blank.gif
│ │ │ ├── loading.gif
│ │ │ ├── tabs_icons.png
│ │ │ ├── tree_icons.png
│ │ │ ├── combo_arrow.png
│ │ │ ├── datebox_arrow.png
│ │ │ ├── layout_arrows.png
│ │ │ ├── linkbutton_bg.png
│ │ │ ├── menu_arrows.png
│ │ │ ├── panel_tools.png
│ │ │ ├── slider_handle.png
│ │ │ ├── tagbox_icons.png
│ │ │ ├── calendar_arrows.png
│ │ │ ├── datagrid_icons.png
│ │ │ ├── messager_icons.png
│ │ │ ├── spinner_arrows.png
│ │ │ ├── accordion_arrows.png
│ │ │ ├── pagination_icons.png
│ │ │ ├── passwordbox_close.png
│ │ │ ├── passwordbox_open.png
│ │ │ ├── searchbox_button.png
│ │ │ └── validatebox_warning.png
│ │ ├── passwordbox.css
│ │ ├── validatebox.css
│ │ ├── splitbutton.css
│ │ ├── filebox.css
│ │ ├── radiobutton.css
│ │ ├── checkbox.css
│ │ ├── combo.css
│ │ ├── datebox.css
│ │ ├── progressbar.css
│ │ ├── propertygrid.css
│ │ ├── combobox.css
│ │ ├── tagbox.css
│ │ ├── messager.css
│ │ ├── dialog.css
│ │ ├── searchbox.css
│ │ ├── sidemenu.css
│ │ ├── pagination.css
│ │ ├── switchbutton.css
│ │ ├── slider.css
│ │ ├── datalist.css
│ │ ├── menubutton.css
│ │ ├── tooltip.css
│ │ ├── accordion.css
│ │ ├── menu.css
│ │ ├── spinner.css
│ │ ├── textbox.css
│ │ ├── layout.css
│ │ ├── tree.css
│ │ ├── calendar.css
│ │ ├── window.css
│ │ ├── linkbutton.css
│ │ ├── panel.css
│ │ └── datagrid.css
│ │ ├── icons
│ │ ├── no.png
│ │ ├── ok.png
│ │ ├── reload.png
│ │ ├── search.png
│ │ ├── edit_add.png
│ │ └── edit_remove.png
│ │ └── icon.css
├── images
│ ├── icons
│ │ ├── device.png
│ │ ├── accessory.png
│ │ ├── gateway.png
│ │ └── homekit.png
│ └── deviceIcons
│ │ ├── Lock.png
│ │ ├── Button.png
│ │ ├── Button2.png
│ │ ├── Button3.png
│ │ ├── Gateway.png
│ │ ├── PlugBase.png
│ │ ├── AcPartner.png
│ │ ├── PlugBase86.png
│ │ ├── Vibration.png
│ │ ├── ContactSensor.png
│ │ ├── DuplexSwitch.png
│ │ ├── MagicSquare.png
│ │ ├── MotionSensor.png
│ │ ├── MotionSensor2.png
│ │ ├── SingleSwitch.png
│ │ ├── SmokeDetector.png
│ │ ├── WaterDetector.png
│ │ ├── ContactSensor2.png
│ │ ├── DuplexButton86.png
│ │ ├── DuplexButton862.png
│ │ ├── DuplexSwitchLN.png
│ │ ├── ElectricCurtain.png
│ │ ├── NatgasDetector.png
│ │ ├── SingleButton86.png
│ │ ├── SingleSwitchLN.png
│ │ ├── TemperatureAndHumiditySensor.png
│ │ └── TemperatureAndHumiditySensor2.png
├── login
│ └── login.html
└── css
│ ├── icon.css
│ └── device_icon.css
├── images
├── Lock.jpg
├── Button.jpg
├── Button2.jpg
├── Button3.jpg
├── Gateway.jpg
├── AcPartner.jpg
├── PlugBase.jpg
├── Vibration.jpg
├── syncValue.png
├── DuplexSwitch.jpg
├── MagicSquare.jpg
├── MotionSensor.jpg
├── PlugBase86.jpg
├── SingleSwitch.jpg
├── ContactSensor.jpg
├── ContactSensor2.jpg
├── Donate-AliPay.jpg
├── Donate-WeChat.jpg
├── DuplexButton86.jpg
├── DuplexSwitchLN.jpg
├── MotionSensor2.jpg
├── NatgasDetector.jpg
├── SingleButton86.jpg
├── SingleSwitchLN.jpg
├── SmokeDetector.jpg
├── WaterDetector.jpg
├── httpWebManage.png
├── DuplexButton862.jpg
├── ElectricCurtain.jpg
├── ElectricCurtainBattery.jpg
├── TemperatureAndHumiditySensor.jpg
└── TemperatureAndHumiditySensor2.jpg
├── lib
├── AccessoryUtil.js
├── GatewayUtil.js
├── LogUtil.js
├── DeviceUtil.js
├── ParseUtil.js
└── ConfigUtil.js
├── package.json
└── parser
├── DeviceParser.js
├── SwitchVirtualBasePressParser.js
├── SmokeDetectorParser.js
├── NatgasDetectorParser.js
├── MotionSensorParser.js
├── ContactSensorParser.js
├── ContactSensor2Parser.js
├── WaterDetectorParser.js
├── PlugBaseParser.js
├── PlugBase86Parser.js
├── ElectricCurtainParser.js
├── SingleSwitchParser.js
├── SingleSwitchLNParser.js
├── VibrationSensorParser.js
├── ElectricCurtainBatteryParser.js
├── LockParser.js
├── DuplexSwitchParser.js
└── DuplexSwitchLNParser.js
/manage/easyui/themes/default/numberbox.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/Lock.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/Lock.jpg
--------------------------------------------------------------------------------
/images/Button.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/Button.jpg
--------------------------------------------------------------------------------
/images/Button2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/Button2.jpg
--------------------------------------------------------------------------------
/images/Button3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/Button3.jpg
--------------------------------------------------------------------------------
/images/Gateway.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/Gateway.jpg
--------------------------------------------------------------------------------
/images/AcPartner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/AcPartner.jpg
--------------------------------------------------------------------------------
/images/PlugBase.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/PlugBase.jpg
--------------------------------------------------------------------------------
/images/Vibration.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/Vibration.jpg
--------------------------------------------------------------------------------
/images/syncValue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/syncValue.png
--------------------------------------------------------------------------------
/images/DuplexSwitch.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/DuplexSwitch.jpg
--------------------------------------------------------------------------------
/images/MagicSquare.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/MagicSquare.jpg
--------------------------------------------------------------------------------
/images/MotionSensor.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/MotionSensor.jpg
--------------------------------------------------------------------------------
/images/PlugBase86.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/PlugBase86.jpg
--------------------------------------------------------------------------------
/images/SingleSwitch.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/SingleSwitch.jpg
--------------------------------------------------------------------------------
/images/ContactSensor.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/ContactSensor.jpg
--------------------------------------------------------------------------------
/images/ContactSensor2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/ContactSensor2.jpg
--------------------------------------------------------------------------------
/images/Donate-AliPay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/Donate-AliPay.jpg
--------------------------------------------------------------------------------
/images/Donate-WeChat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/Donate-WeChat.jpg
--------------------------------------------------------------------------------
/images/DuplexButton86.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/DuplexButton86.jpg
--------------------------------------------------------------------------------
/images/DuplexSwitchLN.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/DuplexSwitchLN.jpg
--------------------------------------------------------------------------------
/images/MotionSensor2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/MotionSensor2.jpg
--------------------------------------------------------------------------------
/images/NatgasDetector.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/NatgasDetector.jpg
--------------------------------------------------------------------------------
/images/SingleButton86.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/SingleButton86.jpg
--------------------------------------------------------------------------------
/images/SingleSwitchLN.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/SingleSwitchLN.jpg
--------------------------------------------------------------------------------
/images/SmokeDetector.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/SmokeDetector.jpg
--------------------------------------------------------------------------------
/images/WaterDetector.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/WaterDetector.jpg
--------------------------------------------------------------------------------
/images/httpWebManage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/httpWebManage.png
--------------------------------------------------------------------------------
/images/DuplexButton862.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/DuplexButton862.jpg
--------------------------------------------------------------------------------
/images/ElectricCurtain.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/ElectricCurtain.jpg
--------------------------------------------------------------------------------
/manage/images/icons/device.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/icons/device.png
--------------------------------------------------------------------------------
/images/ElectricCurtainBattery.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/ElectricCurtainBattery.jpg
--------------------------------------------------------------------------------
/manage/easyui/themes/icons/no.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/icons/no.png
--------------------------------------------------------------------------------
/manage/easyui/themes/icons/ok.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/icons/ok.png
--------------------------------------------------------------------------------
/manage/images/icons/accessory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/icons/accessory.png
--------------------------------------------------------------------------------
/manage/images/icons/gateway.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/icons/gateway.png
--------------------------------------------------------------------------------
/manage/images/icons/homekit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/icons/homekit.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/Lock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/Lock.png
--------------------------------------------------------------------------------
/manage/easyui/themes/icons/reload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/icons/reload.png
--------------------------------------------------------------------------------
/manage/easyui/themes/icons/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/icons/search.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/Button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/Button.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/Button2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/Button2.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/Button3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/Button3.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/Gateway.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/Gateway.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/PlugBase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/PlugBase.png
--------------------------------------------------------------------------------
/images/TemperatureAndHumiditySensor.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/TemperatureAndHumiditySensor.jpg
--------------------------------------------------------------------------------
/images/TemperatureAndHumiditySensor2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/images/TemperatureAndHumiditySensor2.jpg
--------------------------------------------------------------------------------
/manage/easyui/themes/icons/edit_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/icons/edit_add.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/AcPartner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/AcPartner.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/PlugBase86.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/PlugBase86.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/Vibration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/Vibration.png
--------------------------------------------------------------------------------
/manage/easyui/themes/icons/edit_remove.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/icons/edit_remove.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/ContactSensor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/ContactSensor.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/DuplexSwitch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/DuplexSwitch.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/MagicSquare.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/MagicSquare.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/MotionSensor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/MotionSensor.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/MotionSensor2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/MotionSensor2.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/SingleSwitch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/SingleSwitch.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/SmokeDetector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/SmokeDetector.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/WaterDetector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/WaterDetector.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/blank.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/blank.gif
--------------------------------------------------------------------------------
/manage/images/deviceIcons/ContactSensor2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/ContactSensor2.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/DuplexButton86.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/DuplexButton86.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/DuplexButton862.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/DuplexButton862.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/DuplexSwitchLN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/DuplexSwitchLN.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/ElectricCurtain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/ElectricCurtain.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/NatgasDetector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/NatgasDetector.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/SingleButton86.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/SingleButton86.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/SingleSwitchLN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/SingleSwitchLN.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/loading.gif
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/tabs_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/tabs_icons.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/tree_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/tree_icons.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/combo_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/combo_arrow.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/datebox_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/datebox_arrow.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/layout_arrows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/layout_arrows.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/linkbutton_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/linkbutton_bg.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/menu_arrows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/menu_arrows.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/panel_tools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/panel_tools.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/slider_handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/slider_handle.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/tagbox_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/tagbox_icons.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/calendar_arrows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/calendar_arrows.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/datagrid_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/datagrid_icons.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/messager_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/messager_icons.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/spinner_arrows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/spinner_arrows.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/accordion_arrows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/accordion_arrows.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/pagination_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/pagination_icons.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/passwordbox_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/passwordbox_close.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/passwordbox_open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/passwordbox_open.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/searchbox_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/searchbox_button.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/TemperatureAndHumiditySensor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/TemperatureAndHumiditySensor.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/images/validatebox_warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/easyui/themes/default/images/validatebox_warning.png
--------------------------------------------------------------------------------
/manage/images/deviceIcons/TemperatureAndHumiditySensor2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YinHangCode/homebridge-mi-aqara/HEAD/manage/images/deviceIcons/TemperatureAndHumiditySensor2.png
--------------------------------------------------------------------------------
/manage/easyui/themes/default/passwordbox.css:
--------------------------------------------------------------------------------
1 | .passwordbox-open {
2 | background: url('images/passwordbox_open.png') no-repeat center center;
3 | }
4 | .passwordbox-close {
5 | background: url('images/passwordbox_close.png') no-repeat center center;
6 | }
7 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/validatebox.css:
--------------------------------------------------------------------------------
1 | .inputbox {
2 | display: inline-block;
3 | vertical-align: middle;
4 | overflow: hidden;
5 | white-space: nowrap;
6 | margin: 0;
7 | padding: 0;
8 | }
9 | .validatebox-invalid {
10 | border-color: #ffa8a8;
11 | background-color: #fff3f3;
12 | color: #000;
13 | }
14 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/splitbutton.css:
--------------------------------------------------------------------------------
1 | .s-btn:hover .m-btn-line,
2 | .s-btn-active .m-btn-line,
3 | .s-btn-plain-active .m-btn-line {
4 | display: inline-block;
5 | }
6 | .l-btn:hover .s-btn-downarrow,
7 | .s-btn-active .s-btn-downarrow,
8 | .s-btn-plain-active .s-btn-downarrow {
9 | border-style: solid;
10 | border-color: #aac5e7;
11 | border-width: 0 0 0 1px;
12 | }
13 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/filebox.css:
--------------------------------------------------------------------------------
1 | .filebox .textbox-value {
2 | vertical-align: top;
3 | position: absolute;
4 | top: 0;
5 | left: -5000px;
6 | }
7 | .filebox-label {
8 | display: inline-block;
9 | position: absolute;
10 | width: 100%;
11 | height: 100%;
12 | cursor: pointer;
13 | left: 0;
14 | top: 0;
15 | z-index: 10;
16 | background: url('images/blank.gif') no-repeat;
17 | }
18 | .l-btn-disabled .filebox-label {
19 | cursor: default;
20 | }
21 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/radiobutton.css:
--------------------------------------------------------------------------------
1 | .radiobutton {
2 | position: relative;
3 | border: 2px solid #ffab3f;
4 | border-radius: 50%;
5 | }
6 | .radiobutton-inner {
7 | position: absolute;
8 | left: 0;
9 | top: 0;
10 | width: 100%;
11 | height: 100%;
12 | background: #ffab3f;
13 | border-radius: 50%;
14 | transform: scale(.6);
15 | }
16 | .radiobutton-disabled {
17 | opacity: 0.6;
18 | }
19 | .radiobutton-value {
20 | position: absolute;
21 | overflow: hidden;
22 | width: 1px;
23 | height: 1px;
24 | left: -999px;
25 | }
26 |
--------------------------------------------------------------------------------
/lib/AccessoryUtil.js:
--------------------------------------------------------------------------------
1 | class AccessoryUtil {
2 | constructor() {
3 | this.accessories = {};
4 | }
5 |
6 | getByUUID(uuid) {
7 | return (uuid in this.accessories) ? this.accessories[uuid] : null;
8 | }
9 |
10 | add(accessory) {
11 | this.accessories[accessory.UUID] = accessory;
12 | return accessory;
13 | }
14 |
15 | remove(uuid) {
16 | delete this.accessories[uuid];
17 | }
18 |
19 | getAll() {
20 | return this.accessories;
21 | }
22 | }
23 |
24 | module.exports = AccessoryUtil;
--------------------------------------------------------------------------------
/manage/login/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | MiAqara Manage Login
7 |
8 |
9 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/manage/css/icon.css:
--------------------------------------------------------------------------------
1 | .icon-gateway {
2 | background:url('../images/icons/gateway.png') no-repeat center center;
3 | background-size: 16px 16px;
4 | }
5 |
6 | .icon-device {
7 | background:url('../images/icons/device.png') no-repeat center center;
8 | background-size: 16px 16px;
9 | }
10 |
11 | .icon-accessory {
12 | background:url('../images/icons/accessory.png') no-repeat center center;
13 | background-size: 16px 16px;
14 | }
15 |
16 | .icon-homekit {
17 | background:url('../images/icons/homekit.png') no-repeat center center;
18 | background-size: 16px 16px;
19 | }
--------------------------------------------------------------------------------
/manage/easyui/themes/default/checkbox.css:
--------------------------------------------------------------------------------
1 | .checkbox {
2 | position: relative;
3 | border: 2px solid #ffab3f;
4 | -moz-border-radius: 5px 5px 5px 5px;
5 | -webkit-border-radius: 5px 5px 5px 5px;
6 | border-radius: 5px 5px 5px 5px;
7 | }
8 | .checkbox-checked {
9 | border: 0;
10 | background: #ffab3f;
11 | }
12 | .checkbox-inner {
13 | position: absolute;
14 | left: 0;
15 | top: 0;
16 | width: 100%;
17 | height: 100%;
18 | }
19 | .checkbox path {
20 | stroke-width: 2px;
21 | }
22 | .checkbox-disabled {
23 | opacity: 0.6;
24 | }
25 | .checkbox-value {
26 | position: absolute;
27 | overflow: hidden;
28 | width: 1px;
29 | height: 1px;
30 | left: -999px;
31 | }
32 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "homebridge-mi-aqara",
3 | "version": "0.8.1",
4 | "description": "XiaoMi Aqara plugins for HomeBridge(https://github.com/nfarina/homebridge).",
5 | "license": "GPL",
6 | "keywords": [
7 | "homebridge-plugin"
8 | ],
9 | "author": "hang.yin",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/YinHangCode/homebridge-mi-aqara"
13 | },
14 | "bugs": {
15 | "url": "https://github.com/YinHangCode/homebridge-mi-aqara/issues"
16 | },
17 | "engines": {
18 | "node": ">=0.12.0",
19 | "homebridge": ">=0.4.1"
20 | },
21 | "dependencies": {
22 | "body-parser": "1.18.3",
23 | "express": "4.16.3",
24 | "express-session": "1.15.6",
25 | "mqtt": "2.18.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/combo.css:
--------------------------------------------------------------------------------
1 | .combo-arrow {
2 | width: 18px;
3 | height: 20px;
4 | overflow: hidden;
5 | display: inline-block;
6 | vertical-align: top;
7 | cursor: pointer;
8 | opacity: 0.6;
9 | filter: alpha(opacity=60);
10 | }
11 | .combo-arrow-hover {
12 | opacity: 1.0;
13 | filter: alpha(opacity=100);
14 | }
15 | .combo-panel {
16 | overflow: auto;
17 | }
18 | .combo-arrow {
19 | background: url('images/combo_arrow.png') no-repeat center center;
20 | }
21 | .combo-panel {
22 | background-color: #ffffff;
23 | }
24 | .combo-arrow {
25 | background-color: #E0ECFF;
26 | }
27 | .combo-arrow-hover {
28 | background-color: #eaf2ff;
29 | }
30 | .combo-arrow:hover {
31 | background-color: #eaf2ff;
32 | }
33 | .combo .textbox-icon-disabled:hover {
34 | cursor: default;
35 | }
36 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/datebox.css:
--------------------------------------------------------------------------------
1 | .datebox-calendar-inner {
2 | height: 250px;
3 | }
4 | .datebox-button {
5 | padding: 4px 0;
6 | text-align: center;
7 | }
8 | .datebox-button a {
9 | line-height: 22px;
10 | font-size: 14px;
11 | font-weight: bold;
12 | text-decoration: none;
13 | opacity: 0.6;
14 | filter: alpha(opacity=60);
15 | }
16 | .datebox-button a:hover {
17 | opacity: 1.0;
18 | filter: alpha(opacity=100);
19 | }
20 | .datebox-current,
21 | .datebox-close {
22 | float: left;
23 | }
24 | .datebox-close {
25 | float: right;
26 | }
27 | .datebox .combo-arrow {
28 | background-image: url('images/datebox_arrow.png');
29 | background-position: center center;
30 | }
31 | .datebox-button {
32 | background-color: #F4F4F4;
33 | }
34 | .datebox-button a {
35 | color: #444;
36 | }
37 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/progressbar.css:
--------------------------------------------------------------------------------
1 | .progressbar {
2 | border-width: 1px;
3 | border-style: solid;
4 | -moz-border-radius: 5px 5px 5px 5px;
5 | -webkit-border-radius: 5px 5px 5px 5px;
6 | border-radius: 5px 5px 5px 5px;
7 | overflow: hidden;
8 | position: relative;
9 | }
10 | .progressbar-text {
11 | text-align: center;
12 | position: absolute;
13 | }
14 | .progressbar-value {
15 | position: relative;
16 | overflow: hidden;
17 | width: 0;
18 | -moz-border-radius: 5px 0 0 5px;
19 | -webkit-border-radius: 5px 0 0 5px;
20 | border-radius: 5px 0 0 5px;
21 | }
22 | .progressbar {
23 | border-color: #95B8E7;
24 | }
25 | .progressbar-text {
26 | color: #000000;
27 | font-size: 14px;
28 | }
29 | .progressbar-value,
30 | .progressbar-value .progressbar-text {
31 | background-color: #ffe48d;
32 | color: #000000;
33 | }
34 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/propertygrid.css:
--------------------------------------------------------------------------------
1 | .propertygrid .datagrid-view1 .datagrid-body td {
2 | padding-bottom: 1px;
3 | border-width: 0 1px 0 0;
4 | }
5 | .propertygrid .datagrid-group {
6 | overflow: hidden;
7 | border-width: 0 0 1px 0;
8 | border-style: solid;
9 | }
10 | .propertygrid .datagrid-group span {
11 | font-weight: bold;
12 | }
13 | .propertygrid .datagrid-view1 .datagrid-body td {
14 | border-color: #dddddd;
15 | }
16 | .propertygrid .datagrid-view1 .datagrid-group {
17 | border-color: #E0ECFF;
18 | }
19 | .propertygrid .datagrid-view2 .datagrid-group {
20 | border-color: #dddddd;
21 | }
22 | .propertygrid .datagrid-group,
23 | .propertygrid .datagrid-view1 .datagrid-body,
24 | .propertygrid .datagrid-view1 .datagrid-row-over,
25 | .propertygrid .datagrid-view1 .datagrid-row-selected {
26 | background: #E0ECFF;
27 | }
28 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/combobox.css:
--------------------------------------------------------------------------------
1 | .combobox-item,
2 | .combobox-group,
3 | .combobox-stick {
4 | font-size: 14px;
5 | padding: 6px 4px;
6 | line-height: 20px;
7 | }
8 | .combobox-item-disabled {
9 | opacity: 0.5;
10 | filter: alpha(opacity=50);
11 | }
12 | .combobox-gitem {
13 | padding-left: 10px;
14 | }
15 | .combobox-group,
16 | .combobox-stick {
17 | font-weight: bold;
18 | }
19 | .combobox-stick {
20 | position: absolute;
21 | top: 1px;
22 | left: 1px;
23 | right: 1px;
24 | background: inherit;
25 | }
26 | .combobox-item-hover {
27 | background-color: #eaf2ff;
28 | color: #000000;
29 | }
30 | .combobox-item-selected {
31 | background-color: #ffe48d;
32 | color: #000000;
33 | }
34 | .combobox-icon {
35 | display: inline-block;
36 | width: 16px;
37 | height: 16px;
38 | vertical-align: middle;
39 | margin-right: 2px;
40 | }
41 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/tagbox.css:
--------------------------------------------------------------------------------
1 | .tagbox {
2 | cursor: text;
3 | }
4 | .tagbox .textbox-text {
5 | float: left;
6 | }
7 | .tagbox-label {
8 | position: relative;
9 | display: block;
10 | margin: 4px 0 0 4px;
11 | padding: 0 20px 0 4px;
12 | float: left;
13 | vertical-align: top;
14 | text-decoration: none;
15 | -moz-border-radius: 5px 5px 5px 5px;
16 | -webkit-border-radius: 5px 5px 5px 5px;
17 | border-radius: 5px 5px 5px 5px;
18 | background: #eaf2ff;
19 | color: #000000;
20 | }
21 | .tagbox-remove {
22 | background: url('images/tagbox_icons.png') no-repeat -16px center;
23 | position: absolute;
24 | display: block;
25 | width: 16px;
26 | height: 16px;
27 | right: 2px;
28 | top: 50%;
29 | margin-top: -8px;
30 | opacity: 0.6;
31 | filter: alpha(opacity=60);
32 | }
33 | .tagbox-remove:hover {
34 | opacity: 1;
35 | filter: alpha(opacity=100);
36 | }
37 | .textbox-disabled .tagbox-label {
38 | cursor: default;
39 | }
40 | .textbox-disabled .tagbox-remove:hover {
41 | cursor: default;
42 | opacity: 0.6;
43 | filter: alpha(opacity=60);
44 | }
45 |
--------------------------------------------------------------------------------
/lib/GatewayUtil.js:
--------------------------------------------------------------------------------
1 | class GatewayUtil {
2 | constructor() {
3 | this.gateways = {};
4 | }
5 |
6 | getBySid(sid) {
7 | return (sid in this.gateways) ? this.gateways[sid] : null;
8 | }
9 |
10 | add(gateway) {
11 | this.gateways[gateway.sid] = gateway;
12 | return gateway;
13 | }
14 |
15 | update(sid, newGateway) {
16 | var gateway = this.getBySid(sid);
17 | if(null != gateway) {
18 | for(var item in newGateway) {
19 | gateway[item] = newGateway[item];
20 | }
21 | }
22 | return gateway;
23 | }
24 |
25 | addOrUpdate(sid, newGateway) {
26 | var gateway = this.getBySid(sid);
27 | if(null == gateway) {
28 | return this.add(newGateway);
29 | } else {
30 | return this.update(sid, newGateway);
31 | }
32 | }
33 |
34 | remove(sid) {
35 | delete this.gateways[sid];
36 | }
37 |
38 | getAll() {
39 | return this.gateways;
40 | }
41 | }
42 |
43 | module.exports = GatewayUtil;
--------------------------------------------------------------------------------
/manage/easyui/themes/default/messager.css:
--------------------------------------------------------------------------------
1 | .messager-body {
2 | padding: 10px 10px 30px 10px;
3 | overflow: auto;
4 | }
5 | .messager-button {
6 | text-align: center;
7 | padding: 5px;
8 | }
9 | .messager-button .l-btn {
10 | width: 70px;
11 | }
12 | .messager-icon {
13 | float: left;
14 | width: 32px;
15 | height: 32px;
16 | margin: 0 10px 10px 0;
17 | }
18 | .messager-error {
19 | background: url('images/messager_icons.png') no-repeat scroll -64px 0;
20 | }
21 | .messager-info {
22 | background: url('images/messager_icons.png') no-repeat scroll 0 0;
23 | }
24 | .messager-question {
25 | background: url('images/messager_icons.png') no-repeat scroll -32px 0;
26 | }
27 | .messager-warning {
28 | background: url('images/messager_icons.png') no-repeat scroll -96px 0;
29 | }
30 | .messager-progress {
31 | padding: 10px;
32 | }
33 | .messager-p-msg {
34 | margin-bottom: 5px;
35 | }
36 | .messager-body .messager-input {
37 | width: 100%;
38 | padding: 4px 0;
39 | outline-style: none;
40 | border: 1px solid #95B8E7;
41 | }
42 | .window-thinborder .messager-button {
43 | padding-bottom: 8px;
44 | }
45 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/dialog.css:
--------------------------------------------------------------------------------
1 | .dialog-content {
2 | overflow: auto;
3 | }
4 | .dialog-toolbar {
5 | position: relative;
6 | padding: 2px 5px;
7 | }
8 | .dialog-tool-separator {
9 | float: left;
10 | height: 24px;
11 | border-left: 1px solid #ccc;
12 | border-right: 1px solid #fff;
13 | margin: 2px 1px;
14 | }
15 | .dialog-button {
16 | position: relative;
17 | top: -1px;
18 | padding: 5px;
19 | text-align: right;
20 | }
21 | .dialog-button .l-btn {
22 | margin-left: 5px;
23 | }
24 | .dialog-toolbar,
25 | .dialog-button {
26 | background: #F4F4F4;
27 | border-width: 1px;
28 | border-style: solid;
29 | }
30 | .dialog-toolbar {
31 | border-color: #95B8E7 #95B8E7 #dddddd #95B8E7;
32 | }
33 | .dialog-button {
34 | border-color: #dddddd #95B8E7 #95B8E7 #95B8E7;
35 | }
36 | .window-thinborder .dialog-toolbar {
37 | border-left: transparent;
38 | border-right: transparent;
39 | border-top-color: #F4F4F4;
40 | }
41 | .window-thinborder .dialog-button {
42 | top: 0px;
43 | padding: 5px 8px 8px 8px;
44 | border-left: transparent;
45 | border-right: transparent;
46 | border-bottom: transparent;
47 | }
48 |
--------------------------------------------------------------------------------
/lib/LogUtil.js:
--------------------------------------------------------------------------------
1 | class LogUtil {
2 | constructor(flag, log) {
3 | this.flag = flag;
4 | this.log = log;
5 | }
6 |
7 | debug(str) {
8 | this.log.debug(this.flag ? "[" + this.flag + "]" : "" + "[DEBUG]" + str);
9 | }
10 |
11 | info(str) {
12 | this.log.info(this.flag ? "[" + this.flag + "]" : "" + "[INFO]" + str);
13 | }
14 |
15 | warn(str) {
16 | this.log.warn(this.flag ? "[" + this.flag + "]" : "" + "[WARN]" + str);
17 | }
18 |
19 | error(str) {
20 | this.log.error(this.flag ? "[" + this.flag + "]" : "" + "[ERROR]" + str);
21 | if(str instanceof Error) {
22 | this.log.debug(this.flag ? "[" + this.flag + "]" : "" + "[ERROR]" + str.stack);
23 | }
24 | }
25 |
26 | objKey2Str(obj) {
27 | var keys = '';
28 | try {
29 | for(var key in obj) {
30 | keys += key + ', ';
31 | }
32 | keys = keys.substring(0, keys.lastIndexOf(','));
33 | } catch(e) {
34 | }
35 |
36 | return keys;
37 | }
38 | }
39 |
40 | module.exports = LogUtil;
--------------------------------------------------------------------------------
/lib/DeviceUtil.js:
--------------------------------------------------------------------------------
1 | class DeviceUtil {
2 | constructor() {
3 | this.devices = {};
4 | }
5 |
6 | getBySid(sid) {
7 | return (sid in this.devices) ? this.devices[sid] : null;
8 | }
9 |
10 | add(device) {
11 | this.devices[device.sid] = device;
12 | return device;
13 | }
14 |
15 | update(sid, newDevice) {
16 | var device = this.getBySid(sid);
17 | if(null != device) {
18 | for(var item in newDevice) {
19 | device[item] = newDevice[item];
20 | }
21 | }
22 | return device;
23 | }
24 |
25 | addOrUpdate(sid, newDevice) {
26 | var device = this.getBySid(sid);
27 | if(null == device) {
28 | return this.add(newDevice);
29 | } else {
30 | return this.update(sid, newDevice);
31 | }
32 | }
33 |
34 | remove(sid) {
35 | delete this.devices[sid];
36 | }
37 |
38 | getAutoRemoveDevice(threshold) {
39 | var r = {}
40 |
41 | var nowTime = Date.now();
42 | for(var sid in this.devices) {
43 | var device = this.getBySid(sid);
44 | if ((nowTime - device.lastUpdateTime) > threshold) {
45 | r[sid] = device;
46 | }
47 | }
48 |
49 | return r;
50 | }
51 |
52 | getAll() {
53 | return this.devices;
54 | }
55 | }
56 |
57 | module.exports = DeviceUtil;
--------------------------------------------------------------------------------
/parser/DeviceParser.js:
--------------------------------------------------------------------------------
1 | class DeviceParser {
2 | constructor(platform) {
3 | this.platform = platform;
4 |
5 | this.initAccessoriesParser();
6 | }
7 |
8 | getAccessoriesUUID(deviceSid) {
9 | var r = {};
10 |
11 | var parsers = this.accessoriesParsers;
12 | for(var item in parsers) {
13 | r[item] = parsers[item].getAccessoryUUID(deviceSid);
14 | }
15 |
16 | return r;
17 | }
18 |
19 | getAccessoriesParserInfo() {
20 | return {};
21 | }
22 |
23 | initAccessoriesParser() {
24 | this.accessoriesParsers = {};
25 |
26 | var accessoriesParserInfo = this.getAccessoriesParserInfo();
27 | for(var key in accessoriesParserInfo) {
28 | this.accessoriesParsers[key] = new (accessoriesParserInfo[key])(this.platform, key);
29 | }
30 | }
31 |
32 | getCreateAccessories(jsonObj) {
33 | var r = [];
34 |
35 | var parsers = this.accessoriesParsers;
36 | for(var item in parsers) {
37 | var accessory = parsers[item].getCreateAccessories(jsonObj);
38 | if(accessory) {
39 | r.push(accessory);
40 | }
41 | }
42 |
43 | return r;
44 | }
45 |
46 | parserAccessories(jsonObj) {
47 | var parsers = this.accessoriesParsers;
48 | for(var item in parsers) {
49 | parsers[item].parserAccessories(jsonObj);
50 | }
51 | }
52 | }
53 |
54 | module.exports = DeviceParser;
--------------------------------------------------------------------------------
/manage/easyui/themes/default/searchbox.css:
--------------------------------------------------------------------------------
1 | .searchbox-button {
2 | width: 18px;
3 | height: 20px;
4 | overflow: hidden;
5 | display: inline-block;
6 | vertical-align: top;
7 | cursor: pointer;
8 | opacity: 0.6;
9 | filter: alpha(opacity=60);
10 | }
11 | .searchbox-button-hover {
12 | opacity: 1.0;
13 | filter: alpha(opacity=100);
14 | }
15 | .searchbox .l-btn-plain {
16 | border: 0;
17 | padding: 0;
18 | vertical-align: top;
19 | opacity: 0.6;
20 | filter: alpha(opacity=60);
21 | -moz-border-radius: 0 0 0 0;
22 | -webkit-border-radius: 0 0 0 0;
23 | border-radius: 0 0 0 0;
24 | }
25 | .searchbox .l-btn-plain:hover {
26 | border: 0;
27 | padding: 0;
28 | opacity: 1.0;
29 | filter: alpha(opacity=100);
30 | -moz-border-radius: 0 0 0 0;
31 | -webkit-border-radius: 0 0 0 0;
32 | border-radius: 0 0 0 0;
33 | }
34 | .searchbox a.m-btn-plain-active {
35 | -moz-border-radius: 0 0 0 0;
36 | -webkit-border-radius: 0 0 0 0;
37 | border-radius: 0 0 0 0;
38 | }
39 | .searchbox .m-btn-active {
40 | border-width: 0 1px 0 0;
41 | -moz-border-radius: 0 0 0 0;
42 | -webkit-border-radius: 0 0 0 0;
43 | border-radius: 0 0 0 0;
44 | }
45 | .searchbox .textbox-button-right {
46 | border-width: 0 0 0 1px;
47 | }
48 | .searchbox .textbox-button-left {
49 | border-width: 0 1px 0 0;
50 | }
51 | .searchbox-button {
52 | background: url('images/searchbox_button.png') no-repeat center center;
53 | }
54 | .searchbox .l-btn-plain {
55 | background: #E0ECFF;
56 | }
57 | .searchbox .l-btn-plain-disabled,
58 | .searchbox .l-btn-plain-disabled:hover {
59 | opacity: 0.5;
60 | filter: alpha(opacity=50);
61 | }
62 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/sidemenu.css:
--------------------------------------------------------------------------------
1 | .sidemenu .tree-hit {
2 | background-image: none;
3 | }
4 | .sidemenu-default-icon {
5 | background-image: none;
6 | width: 0;
7 | }
8 | .sidemenu .accordion .accordion-header,
9 | .sidemenu .accordion .accordion-body {
10 | border-bottom-color: transparent;
11 | background: transparent;
12 | }
13 | .sidemenu .accordion .accordion-header {
14 | color: #0E2D5F;
15 | }
16 | .sidemenu .accordion-header .panel-title {
17 | height: 30px;
18 | line-height: 30px;
19 | color: #0E2D5F;
20 | }
21 | .sidemenu .accordion-header:hover {
22 | background: #eaf2ff;
23 | color: #0E2D5F;
24 | }
25 | .sidemenu .tree-node-hover {
26 | background: #eaf2ff;
27 | color: #0E2D5F;
28 | }
29 | .sidemenu .tree-node-selected {
30 | border-right: 2px solid #ffab3f;
31 | color: #000000;
32 | background: #ffe48d;
33 | }
34 | .sidemenu .tree-node {
35 | height: 40px;
36 | }
37 | .sidemenu .tree-title {
38 | margin: 11px 0;
39 | }
40 | .sidemenu .tree-node-nonleaf {
41 | position: relative;
42 | }
43 | .sidemenu .tree-node-nonleaf::after {
44 | display: inline-block;
45 | content: '';
46 | position: absolute;
47 | top: 50%;
48 | margin-top: -8px;
49 | background: url('images/accordion_arrows.png') no-repeat 0 0;
50 | width: 16px;
51 | height: 16px;
52 | right: 5px;
53 | }
54 | .sidemenu .tree-node-nonleaf-collapsed::after {
55 | background: url('images/accordion_arrows.png') no-repeat -16px 0;
56 | }
57 | .sidemenu-collapsed .panel-icon {
58 | left: 50%;
59 | margin-left: -8px;
60 | }
61 | .sidemenu-tooltip {
62 | padding: 0;
63 | margin: 0 -12px;
64 | border: 0;
65 | }
66 | .sidemenu-tooltip.tooltip-left {
67 | margin: 0 12px;
68 | }
69 | .sidemenu-tooltip .tooltip-arrow-outer,
70 | .sidemenu-tooltip .tooltip-arrow {
71 | display: none;
72 | }
73 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/pagination.css:
--------------------------------------------------------------------------------
1 | .pagination {
2 | zoom: 1;
3 | padding: 2px;
4 | }
5 | .pagination table {
6 | float: left;
7 | height: 30px;
8 | }
9 | .pagination td {
10 | border: 0;
11 | }
12 | .pagination-btn-separator {
13 | float: left;
14 | height: 24px;
15 | border-left: 1px solid #ccc;
16 | border-right: 1px solid #fff;
17 | margin: 3px 1px;
18 | }
19 | .pagination .pagination-num {
20 | border-width: 1px;
21 | border-style: solid;
22 | margin: 0 2px;
23 | padding: 2px;
24 | width: 3em;
25 | height: auto;
26 | text-align: center;
27 | font-size: 14px;
28 | }
29 | .pagination-page-list {
30 | margin: 0px 6px;
31 | padding: 1px 2px;
32 | width: auto;
33 | height: auto;
34 | border-width: 1px;
35 | border-style: solid;
36 | }
37 | .pagination-info {
38 | float: right;
39 | margin: 0 6px;
40 | padding: 0;
41 | height: 30px;
42 | line-height: 30px;
43 | font-size: 14px;
44 | }
45 | .pagination span {
46 | font-size: 14px;
47 | }
48 | .pagination-link .l-btn-text {
49 | box-sizing: border-box;
50 | text-align: center;
51 | margin: 0;
52 | padding: 0 .5em;
53 | width: auto;
54 | min-width: 28px;
55 | }
56 | .pagination-first {
57 | background: url('images/pagination_icons.png') no-repeat 0 center;
58 | }
59 | .pagination-prev {
60 | background: url('images/pagination_icons.png') no-repeat -16px center;
61 | }
62 | .pagination-next {
63 | background: url('images/pagination_icons.png') no-repeat -32px center;
64 | }
65 | .pagination-last {
66 | background: url('images/pagination_icons.png') no-repeat -48px center;
67 | }
68 | .pagination-load {
69 | background: url('images/pagination_icons.png') no-repeat -64px center;
70 | }
71 | .pagination-loading {
72 | background: url('images/loading.gif') no-repeat center center;
73 | }
74 | .pagination-page-list,
75 | .pagination .pagination-num {
76 | border-color: #95B8E7;
77 | }
78 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/switchbutton.css:
--------------------------------------------------------------------------------
1 | .switchbutton {
2 | text-decoration: none;
3 | display: inline-block;
4 | overflow: hidden;
5 | vertical-align: middle;
6 | margin: 0;
7 | padding: 0;
8 | cursor: pointer;
9 | background: #bbb;
10 | border: 1px solid #bbb;
11 | -moz-border-radius: 5px 5px 5px 5px;
12 | -webkit-border-radius: 5px 5px 5px 5px;
13 | border-radius: 5px 5px 5px 5px;
14 | }
15 | .switchbutton-inner {
16 | display: inline-block;
17 | overflow: hidden;
18 | position: relative;
19 | top: -1px;
20 | left: -1px;
21 | }
22 | .switchbutton-on,
23 | .switchbutton-off,
24 | .switchbutton-handle {
25 | display: inline-block;
26 | text-align: center;
27 | height: 100%;
28 | float: left;
29 | font-size: 14px;
30 | -moz-border-radius: 5px 5px 5px 5px;
31 | -webkit-border-radius: 5px 5px 5px 5px;
32 | border-radius: 5px 5px 5px 5px;
33 | }
34 | .switchbutton-on {
35 | background: #ffe48d;
36 | color: #000000;
37 | }
38 | .switchbutton-off {
39 | background-color: #ffffff;
40 | color: #000000;
41 | }
42 | .switchbutton-on,
43 | .switchbutton-reversed .switchbutton-off {
44 | -moz-border-radius: 5px 0 0 5px;
45 | -webkit-border-radius: 5px 0 0 5px;
46 | border-radius: 5px 0 0 5px;
47 | }
48 | .switchbutton-off,
49 | .switchbutton-reversed .switchbutton-on {
50 | -moz-border-radius: 0 5px 5px 0;
51 | -webkit-border-radius: 0 5px 5px 0;
52 | border-radius: 0 5px 5px 0;
53 | }
54 | .switchbutton-handle {
55 | position: absolute;
56 | top: 0;
57 | left: 50%;
58 | background-color: #ffffff;
59 | color: #000000;
60 | border: 1px solid #bbb;
61 | -moz-box-shadow: 0 0 3px 0 #bbb;
62 | -webkit-box-shadow: 0 0 3px 0 #bbb;
63 | box-shadow: 0 0 3px 0 #bbb;
64 | }
65 | .switchbutton-value {
66 | position: absolute;
67 | top: 0;
68 | left: -5000px;
69 | }
70 | .switchbutton-disabled {
71 | opacity: 0.5;
72 | filter: alpha(opacity=50);
73 | }
74 | .switchbutton-disabled,
75 | .switchbutton-readonly {
76 | cursor: default;
77 | }
78 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/slider.css:
--------------------------------------------------------------------------------
1 | .slider-disabled {
2 | opacity: 0.5;
3 | filter: alpha(opacity=50);
4 | }
5 | .slider-h {
6 | height: 22px;
7 | }
8 | .slider-v {
9 | width: 22px;
10 | }
11 | .slider-inner {
12 | position: relative;
13 | height: 6px;
14 | top: 7px;
15 | border-width: 1px;
16 | border-style: solid;
17 | border-radius: 5px;
18 | }
19 | .slider-handle {
20 | position: absolute;
21 | display: block;
22 | outline: none;
23 | width: 20px;
24 | height: 20px;
25 | top: 50%;
26 | margin-top: -10px;
27 | margin-left: -10px;
28 | }
29 | .slider-tip {
30 | position: absolute;
31 | display: inline-block;
32 | line-height: 12px;
33 | font-size: 14px;
34 | white-space: nowrap;
35 | top: -22px;
36 | }
37 | .slider-rule {
38 | position: relative;
39 | top: 15px;
40 | }
41 | .slider-rule span {
42 | position: absolute;
43 | display: inline-block;
44 | font-size: 0;
45 | height: 5px;
46 | border-width: 0 0 0 1px;
47 | border-style: solid;
48 | }
49 | .slider-rulelabel {
50 | position: relative;
51 | top: 20px;
52 | }
53 | .slider-rulelabel span {
54 | position: absolute;
55 | display: inline-block;
56 | font-size: 14px;
57 | }
58 | .slider-v .slider-inner {
59 | width: 6px;
60 | left: 7px;
61 | top: 0;
62 | float: left;
63 | }
64 | .slider-v .slider-handle {
65 | left: 50%;
66 | margin-top: -10px;
67 | }
68 | .slider-v .slider-tip {
69 | left: -10px;
70 | margin-top: -6px;
71 | }
72 | .slider-v .slider-rule {
73 | float: left;
74 | top: 0;
75 | left: 16px;
76 | }
77 | .slider-v .slider-rule span {
78 | width: 5px;
79 | height: 'auto';
80 | border-left: 0;
81 | border-width: 1px 0 0 0;
82 | border-style: solid;
83 | }
84 | .slider-v .slider-rulelabel {
85 | float: left;
86 | top: 0;
87 | left: 23px;
88 | }
89 | .slider-handle {
90 | background: url('images/slider_handle.png') no-repeat;
91 | }
92 | .slider-inner {
93 | border-color: #95B8E7;
94 | background: #E0ECFF;
95 | }
96 | .slider-rule span {
97 | border-color: #95B8E7;
98 | }
99 | .slider-rulelabel span {
100 | color: #000000;
101 | }
102 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/datalist.css:
--------------------------------------------------------------------------------
1 | .datalist .datagrid-header {
2 | border-width: 0;
3 | }
4 | .datalist .datagrid-group,
5 | .m-list .m-list-group {
6 | height: 25px;
7 | line-height: 25px;
8 | font-weight: bold;
9 | overflow: hidden;
10 | background-color: #efefef;
11 | border-style: solid;
12 | border-width: 0 0 1px 0;
13 | border-color: #ccc;
14 | }
15 | .datalist .datagrid-group-expander {
16 | display: none;
17 | }
18 | .datalist .datagrid-group-title {
19 | padding: 0 4px;
20 | }
21 | .datalist .datagrid-btable {
22 | width: 100%;
23 | table-layout: fixed;
24 | }
25 | .datalist .datagrid-row td {
26 | border-style: solid;
27 | border-left-color: transparent;
28 | border-right-color: transparent;
29 | border-bottom-width: 0;
30 | }
31 | .datalist-lines .datagrid-row td {
32 | border-bottom-width: 1px;
33 | }
34 | .datalist .datagrid-cell,
35 | .m-list li {
36 | width: auto;
37 | height: auto;
38 | padding: 2px 4px;
39 | line-height: 18px;
40 | position: relative;
41 | white-space: nowrap;
42 | text-overflow: ellipsis;
43 | overflow: hidden;
44 | }
45 | .datalist-link,
46 | .m-list li>a {
47 | display: block;
48 | position: relative;
49 | cursor: pointer;
50 | color: #000000;
51 | text-decoration: none;
52 | overflow: hidden;
53 | margin: -2px -4px;
54 | padding: 2px 4px;
55 | padding-right: 16px;
56 | line-height: 18px;
57 | white-space: nowrap;
58 | text-overflow: ellipsis;
59 | overflow: hidden;
60 | }
61 | .datalist-link::after,
62 | .m-list li>a::after {
63 | position: absolute;
64 | display: block;
65 | width: 8px;
66 | height: 8px;
67 | content: '';
68 | right: 6px;
69 | top: 50%;
70 | margin-top: -4px;
71 | border-style: solid;
72 | border-width: 1px 1px 0 0;
73 | -ms-transform: rotate(45deg);
74 | -moz-transform: rotate(45deg);
75 | -webkit-transform: rotate(45deg);
76 | -o-transform: rotate(45deg);
77 | transform: rotate(45deg);
78 | }
79 | .m-list {
80 | margin: 0;
81 | padding: 0;
82 | list-style: none;
83 | }
84 | .m-list li {
85 | border-style: solid;
86 | border-width: 0 0 1px 0;
87 | border-color: #ccc;
88 | }
89 | .m-list li>a:hover {
90 | background: #eaf2ff;
91 | color: #000000;
92 | }
93 | .m-list .m-list-group {
94 | padding: 0 4px;
95 | }
96 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/menubutton.css:
--------------------------------------------------------------------------------
1 | .m-btn-downarrow,
2 | .s-btn-downarrow {
3 | display: inline-block;
4 | position: absolute;
5 | width: 16px;
6 | height: 16px;
7 | font-size: 1px;
8 | right: 0;
9 | top: 50%;
10 | margin-top: -8px;
11 | }
12 | .m-btn-active,
13 | .s-btn-active {
14 | background: #eaf2ff;
15 | color: #000000;
16 | border: 1px solid #b7d2ff;
17 | filter: none;
18 | }
19 | .m-btn-plain-active,
20 | .s-btn-plain-active {
21 | background: transparent;
22 | padding: 0;
23 | border-width: 1px;
24 | border-style: solid;
25 | -moz-border-radius: 5px 5px 5px 5px;
26 | -webkit-border-radius: 5px 5px 5px 5px;
27 | border-radius: 5px 5px 5px 5px;
28 | }
29 | .m-btn .l-btn-left .l-btn-text {
30 | margin-right: 20px;
31 | }
32 | .m-btn .l-btn-icon-right .l-btn-text {
33 | margin-right: 40px;
34 | }
35 | .m-btn .l-btn-icon-right .l-btn-icon {
36 | right: 20px;
37 | }
38 | .m-btn .l-btn-icon-top .l-btn-text {
39 | margin-right: 4px;
40 | margin-bottom: 14px;
41 | }
42 | .m-btn .l-btn-icon-bottom .l-btn-text {
43 | margin-right: 4px;
44 | margin-bottom: 34px;
45 | }
46 | .m-btn .l-btn-icon-bottom .l-btn-icon {
47 | top: auto;
48 | bottom: 20px;
49 | }
50 | .m-btn .l-btn-icon-top .m-btn-downarrow,
51 | .m-btn .l-btn-icon-bottom .m-btn-downarrow {
52 | top: auto;
53 | bottom: 0px;
54 | left: 50%;
55 | margin-left: -8px;
56 | }
57 | .m-btn-line {
58 | display: inline-block;
59 | position: absolute;
60 | font-size: 1px;
61 | display: none;
62 | }
63 | .m-btn .l-btn-left .m-btn-line {
64 | right: 0;
65 | width: 16px;
66 | height: 500px;
67 | border-style: solid;
68 | border-color: #aac5e7;
69 | border-width: 0 0 0 1px;
70 | }
71 | .m-btn .l-btn-icon-top .m-btn-line,
72 | .m-btn .l-btn-icon-bottom .m-btn-line {
73 | left: 0;
74 | bottom: 0;
75 | width: 500px;
76 | height: 16px;
77 | border-width: 1px 0 0 0;
78 | }
79 | .m-btn-large .l-btn-icon-right .l-btn-text {
80 | margin-right: 56px;
81 | }
82 | .m-btn-large .l-btn-icon-bottom .l-btn-text {
83 | margin-bottom: 50px;
84 | }
85 | .m-btn-downarrow,
86 | .s-btn-downarrow {
87 | background: url('images/menu_arrows.png') no-repeat 0 center;
88 | }
89 | .m-btn-plain-active,
90 | .s-btn-plain-active {
91 | border-color: #b7d2ff;
92 | background-color: #eaf2ff;
93 | color: #000000;
94 | }
95 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/tooltip.css:
--------------------------------------------------------------------------------
1 | .tooltip {
2 | position: absolute;
3 | display: none;
4 | z-index: 9900000;
5 | outline: none;
6 | opacity: 1;
7 | filter: alpha(opacity=100);
8 | padding: 5px;
9 | border-width: 1px;
10 | border-style: solid;
11 | border-radius: 5px;
12 | -moz-border-radius: 5px 5px 5px 5px;
13 | -webkit-border-radius: 5px 5px 5px 5px;
14 | border-radius: 5px 5px 5px 5px;
15 | }
16 | .tooltip-content {
17 | font-size: 14px;
18 | }
19 | .tooltip-arrow-outer,
20 | .tooltip-arrow {
21 | position: absolute;
22 | width: 0;
23 | height: 0;
24 | line-height: 0;
25 | font-size: 0;
26 | border-style: solid;
27 | border-width: 6px;
28 | border-color: transparent;
29 | _border-color: tomato;
30 | _filter: chroma(color=tomato);
31 | }
32 | .tooltip-arrow {
33 | display: none \9;
34 | }
35 | .tooltip-right .tooltip-arrow-outer {
36 | left: 0;
37 | top: 50%;
38 | margin: -6px 0 0 -13px;
39 | }
40 | .tooltip-right .tooltip-arrow {
41 | left: 0;
42 | top: 50%;
43 | margin: -6px 0 0 -12px;
44 | }
45 | .tooltip-left .tooltip-arrow-outer {
46 | right: 0;
47 | top: 50%;
48 | margin: -6px -13px 0 0;
49 | }
50 | .tooltip-left .tooltip-arrow {
51 | right: 0;
52 | top: 50%;
53 | margin: -6px -12px 0 0;
54 | }
55 | .tooltip-top .tooltip-arrow-outer {
56 | bottom: 0;
57 | left: 50%;
58 | margin: 0 0 -13px -6px;
59 | }
60 | .tooltip-top .tooltip-arrow {
61 | bottom: 0;
62 | left: 50%;
63 | margin: 0 0 -12px -6px;
64 | }
65 | .tooltip-bottom .tooltip-arrow-outer {
66 | top: 0;
67 | left: 50%;
68 | margin: -13px 0 0 -6px;
69 | }
70 | .tooltip-bottom .tooltip-arrow {
71 | top: 0;
72 | left: 50%;
73 | margin: -12px 0 0 -6px;
74 | }
75 | .tooltip {
76 | background-color: #ffffff;
77 | border-color: #95B8E7;
78 | color: #000000;
79 | }
80 | .tooltip-right .tooltip-arrow-outer {
81 | border-right-color: #95B8E7;
82 | }
83 | .tooltip-right .tooltip-arrow {
84 | border-right-color: #ffffff;
85 | }
86 | .tooltip-left .tooltip-arrow-outer {
87 | border-left-color: #95B8E7;
88 | }
89 | .tooltip-left .tooltip-arrow {
90 | border-left-color: #ffffff;
91 | }
92 | .tooltip-top .tooltip-arrow-outer {
93 | border-top-color: #95B8E7;
94 | }
95 | .tooltip-top .tooltip-arrow {
96 | border-top-color: #ffffff;
97 | }
98 | .tooltip-bottom .tooltip-arrow-outer {
99 | border-bottom-color: #95B8E7;
100 | }
101 | .tooltip-bottom .tooltip-arrow {
102 | border-bottom-color: #ffffff;
103 | }
104 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/accordion.css:
--------------------------------------------------------------------------------
1 | .accordion {
2 | overflow: hidden;
3 | border-width: 1px;
4 | border-style: solid;
5 | }
6 | .accordion .accordion-header {
7 | border-width: 0 0 1px;
8 | cursor: pointer;
9 | }
10 | .accordion .accordion-body {
11 | border-width: 0 0 1px;
12 | }
13 | .accordion-noborder {
14 | border-width: 0;
15 | }
16 | .accordion-noborder .accordion-header {
17 | border-width: 0 0 1px;
18 | }
19 | .accordion-noborder .accordion-body {
20 | border-width: 0 0 1px;
21 | }
22 | .accordion-collapse {
23 | background: url('images/accordion_arrows.png') no-repeat 0 0;
24 | }
25 | .accordion-expand {
26 | background: url('images/accordion_arrows.png') no-repeat -16px 0;
27 | }
28 | .accordion {
29 | background: #ffffff;
30 | border-color: #95B8E7;
31 | }
32 | .accordion .accordion-header {
33 | background: #E0ECFF;
34 | filter: none;
35 | }
36 | .accordion .accordion-header-selected {
37 | background: #ffe48d;
38 | }
39 | .accordion .accordion-header-selected .panel-title {
40 | color: #000000;
41 | }
42 | .accordion .panel-last > .accordion-header {
43 | border-bottom-color: #E0ECFF;
44 | }
45 | .accordion .panel-last > .accordion-body {
46 | border-bottom-color: #ffffff;
47 | }
48 | .accordion .panel-last > .accordion-header-selected,
49 | .accordion .panel-last > .accordion-header-border {
50 | border-bottom-color: #95B8E7;
51 | }
52 | .accordion> .panel-hleft {
53 | float: left;
54 | }
55 | .accordion> .panel-hleft>.panel-header {
56 | border-width: 0 1px 0 0;
57 | }
58 | .accordion> .panel-hleft> .panel-body {
59 | border-width: 0 1px 0 0;
60 | }
61 | .accordion> .panel-hleft.panel-last > .accordion-header {
62 | border-right-color: #E0ECFF;
63 | }
64 | .accordion> .panel-hleft.panel-last > .accordion-body {
65 | border-right-color: #ffffff;
66 | }
67 | .accordion> .panel-hleft.panel-last > .accordion-header-selected,
68 | .accordion> .panel-hleft.panel-last > .accordion-header-border {
69 | border-right-color: #95B8E7;
70 | }
71 | .accordion> .panel-hright {
72 | float: right;
73 | }
74 | .accordion> .panel-hright>.panel-header {
75 | border-width: 0 0 0 1px;
76 | }
77 | .accordion> .panel-hright> .panel-body {
78 | border-width: 0 0 0 1px;
79 | }
80 | .accordion> .panel-hright.panel-last > .accordion-header {
81 | border-left-color: #E0ECFF;
82 | }
83 | .accordion> .panel-hright.panel-last > .accordion-body {
84 | border-left-color: #ffffff;
85 | }
86 | .accordion> .panel-hright.panel-last > .accordion-header-selected,
87 | .accordion> .panel-hright.panel-last > .accordion-header-border {
88 | border-left-color: #95B8E7;
89 | }
90 |
--------------------------------------------------------------------------------
/manage/easyui/themes/icon.css:
--------------------------------------------------------------------------------
1 | .icon-blank{
2 | background:url('icons/blank.gif') no-repeat center center;
3 | }
4 | .icon-add{
5 | background:url('icons/edit_add.png') no-repeat center center;
6 | }
7 | .icon-edit{
8 | background:url('icons/pencil.png') no-repeat center center;
9 | }
10 | .icon-clear{
11 | background:url('icons/clear.png') no-repeat center center;
12 | }
13 | .icon-remove{
14 | background:url('icons/edit_remove.png') no-repeat center center;
15 | }
16 | .icon-save{
17 | background:url('icons/filesave.png') no-repeat center center;
18 | }
19 | .icon-cut{
20 | background:url('icons/cut.png') no-repeat center center;
21 | }
22 | .icon-ok{
23 | background:url('icons/ok.png') no-repeat center center;
24 | }
25 | .icon-no{
26 | background:url('icons/no.png') no-repeat center center;
27 | }
28 | .icon-cancel{
29 | background:url('icons/cancel.png') no-repeat center center;
30 | }
31 | .icon-reload{
32 | background:url('icons/reload.png') no-repeat center center;
33 | }
34 | .icon-search{
35 | background:url('icons/search.png') no-repeat center center;
36 | }
37 | .icon-print{
38 | background:url('icons/print.png') no-repeat center center;
39 | }
40 | .icon-help{
41 | background:url('icons/help.png') no-repeat center center;
42 | }
43 | .icon-undo{
44 | background:url('icons/undo.png') no-repeat center center;
45 | }
46 | .icon-redo{
47 | background:url('icons/redo.png') no-repeat center center;
48 | }
49 | .icon-back{
50 | background:url('icons/back.png') no-repeat center center;
51 | }
52 | .icon-sum{
53 | background:url('icons/sum.png') no-repeat center center;
54 | }
55 | .icon-tip{
56 | background:url('icons/tip.png') no-repeat center center;
57 | }
58 | .icon-filter{
59 | background:url('icons/filter.png') no-repeat center center;
60 | }
61 | .icon-man{
62 | background:url('icons/man.png') no-repeat center center;
63 | }
64 | .icon-lock{
65 | background:url('icons/lock.png') no-repeat center center;
66 | }
67 | .icon-more{
68 | background:url('icons/more.png') no-repeat center center;
69 | }
70 |
71 |
72 | .icon-mini-add{
73 | background:url('icons/mini_add.png') no-repeat center center;
74 | }
75 | .icon-mini-edit{
76 | background:url('icons/mini_edit.png') no-repeat center center;
77 | }
78 | .icon-mini-refresh{
79 | background:url('icons/mini_refresh.png') no-repeat center center;
80 | }
81 |
82 | .icon-large-picture{
83 | background:url('icons/large_picture.png') no-repeat center center;
84 | }
85 | .icon-large-clipart{
86 | background:url('icons/large_clipart.png') no-repeat center center;
87 | }
88 | .icon-large-shapes{
89 | background:url('icons/large_shapes.png') no-repeat center center;
90 | }
91 | .icon-large-smartart{
92 | background:url('icons/large_smartart.png') no-repeat center center;
93 | }
94 | .icon-large-chart{
95 | background:url('icons/large_chart.png') no-repeat center center;
96 | }
97 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/menu.css:
--------------------------------------------------------------------------------
1 | .menu {
2 | position: absolute;
3 | margin: 0;
4 | padding: 2px;
5 | border-width: 1px;
6 | border-style: solid;
7 | overflow: hidden;
8 | }
9 | .menu-inline {
10 | position: relative;
11 | }
12 | .menu-item {
13 | position: relative;
14 | margin: 0;
15 | padding: 0;
16 | overflow: hidden;
17 | white-space: nowrap;
18 | cursor: pointer;
19 | border-width: 1px;
20 | border-style: solid;
21 | }
22 | .menu-text {
23 | height: 20px;
24 | line-height: 20px;
25 | float: left;
26 | padding-left: 28px;
27 | }
28 | .menu-icon {
29 | position: absolute;
30 | width: 16px;
31 | height: 16px;
32 | left: 2px;
33 | top: 50%;
34 | margin-top: -8px;
35 | }
36 | .menu-rightarrow {
37 | position: absolute;
38 | width: 16px;
39 | height: 16px;
40 | right: 0;
41 | top: 50%;
42 | margin-top: -8px;
43 | }
44 | .menu-line {
45 | position: absolute;
46 | left: 26px;
47 | top: 0;
48 | height: 2000px;
49 | font-size: 1px;
50 | }
51 | .menu-sep {
52 | margin: 3px 0px 3px 25px;
53 | font-size: 1px;
54 | }
55 | .menu-noline .menu-line {
56 | display: none;
57 | }
58 | .menu-noline .menu-sep {
59 | margin-left: 0;
60 | margin-right: 0;
61 | }
62 | .menu-active {
63 | -moz-border-radius: 5px 5px 5px 5px;
64 | -webkit-border-radius: 5px 5px 5px 5px;
65 | border-radius: 5px 5px 5px 5px;
66 | }
67 | .menu-item-disabled {
68 | opacity: 0.5;
69 | filter: alpha(opacity=50);
70 | cursor: default;
71 | }
72 | .menu-text,
73 | .menu-text span {
74 | font-size: 14px;
75 | }
76 | .menu-shadow {
77 | position: absolute;
78 | -moz-border-radius: 5px 5px 5px 5px;
79 | -webkit-border-radius: 5px 5px 5px 5px;
80 | border-radius: 5px 5px 5px 5px;
81 | background: #ccc;
82 | -moz-box-shadow: 2px 2px 3px #cccccc;
83 | -webkit-box-shadow: 2px 2px 3px #cccccc;
84 | box-shadow: 2px 2px 3px #cccccc;
85 | filter: progid:DXImageTransform.Microsoft.Blur(pixelRadius=2,MakeShadow=false,ShadowOpacity=0.2);
86 | }
87 | .menu-rightarrow {
88 | background: url('images/menu_arrows.png') no-repeat -32px center;
89 | }
90 | .menu-line {
91 | border-left: 1px solid #ccc;
92 | border-right: 1px solid #fff;
93 | }
94 | .menu-sep {
95 | border-top: 1px solid #ccc;
96 | border-bottom: 1px solid #fff;
97 | }
98 | .menu {
99 | background-color: #fafafa;
100 | border-color: #ddd;
101 | color: #444;
102 | }
103 | .menu-content {
104 | background: #ffffff;
105 | }
106 | .menu-item {
107 | border-color: transparent;
108 | _border-color: #fafafa;
109 | }
110 | .menu-active {
111 | border-color: #b7d2ff;
112 | color: #000000;
113 | background: #eaf2ff;
114 | }
115 | .menu-active-disabled {
116 | border-color: transparent;
117 | background: transparent;
118 | color: #444;
119 | }
120 |
--------------------------------------------------------------------------------
/parser/SwitchVirtualBasePressParser.js:
--------------------------------------------------------------------------------
1 | const AccessoryParser = require('./AccessoryParser');
2 |
3 | class SwitchVirtualBasePressParser extends AccessoryParser {
4 | constructor(platform, accessoryType) {
5 | super(platform, accessoryType)
6 | }
7 |
8 | getAccessoryCategory(deviceSid) {
9 | return this.Accessory.Categories.SWITCH;
10 | }
11 |
12 | getServices(jsonObj, accessoryName) {
13 | var that = this;
14 | var result = [];
15 |
16 | var service = new that.Service.Switch(accessoryName);
17 | service.getCharacteristic(that.Characteristic.On);
18 | result.push(service);
19 |
20 | var batteryService = new that.Service.BatteryService(accessoryName);
21 | batteryService.getCharacteristic(that.Characteristic.StatusLowBattery);
22 | batteryService.getCharacteristic(that.Characteristic.BatteryLevel);
23 | batteryService.getCharacteristic(that.Characteristic.ChargingState);
24 | result.push(batteryService);
25 |
26 | return result;
27 | }
28 |
29 | parserAccessories(jsonObj) {
30 | var that = this;
31 | var deviceSid = jsonObj['sid'];
32 | var uuid = that.getAccessoryUUID(deviceSid);
33 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
34 | if(accessory) {
35 | var service = accessory.getService(that.Service.Switch);
36 | var onCharacteristic = service.getCharacteristic(that.Characteristic.On);
37 |
38 | if(onCharacteristic.listeners('set').length == 0) {
39 | onCharacteristic.on("set", function(value, callback) {
40 | var command = that.getWriteCommand(deviceSid, value);
41 | if(that.platform.ConfigUtil.getAccessoryIgnoreWriteResult(deviceSid, that.accessoryType)) {
42 | that.platform.sendWriteCommandWithoutFeedback(deviceSid, command);
43 | that.callback2HB(deviceSid, this, callback, null);
44 | that.doSomething(jsonObj);
45 | setTimeout(() => {
46 | onCharacteristic.updateValue(false);
47 | }, 10);
48 | } else {
49 | that.platform.sendWriteCommand(deviceSid, command).then(result => {
50 | that.callback2HB(deviceSid, this, callback, null);
51 | that.doSomething(jsonObj);
52 | setTimeout(() => {
53 | onCharacteristic.updateValue(false);
54 | }, 10);
55 | }).catch(function(err) {
56 | that.platform.log.error(err);
57 | that.callback2HB(deviceSid, this, callback, err);
58 | });
59 | }
60 | });
61 | }
62 |
63 | that.parserBatteryService(accessory, jsonObj);
64 | }
65 | }
66 |
67 | doSomething(jsonObj) {
68 | }
69 | }
70 |
71 | module.exports = SwitchVirtualBasePressParser;
72 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/spinner.css:
--------------------------------------------------------------------------------
1 | .spinner-arrow {
2 | display: inline-block;
3 | overflow: hidden;
4 | vertical-align: top;
5 | margin: 0;
6 | padding: 0;
7 | opacity: 1.0;
8 | filter: alpha(opacity=100);
9 | width: 18px;
10 | }
11 | .spinner-arrow.spinner-button-top,
12 | .spinner-arrow.spinner-button-bottom,
13 | .spinner-arrow.spinner-button-left,
14 | .spinner-arrow.spinner-button-right {
15 | background-color: #E0ECFF;
16 | }
17 | .spinner-arrow-up,
18 | .spinner-arrow-down {
19 | opacity: 0.6;
20 | filter: alpha(opacity=60);
21 | display: block;
22 | font-size: 1px;
23 | width: 18px;
24 | height: 10px;
25 | width: 100%;
26 | height: 50%;
27 | color: #444;
28 | outline-style: none;
29 | background-color: #E0ECFF;
30 | }
31 | .spinner-button-updown {
32 | opacity: 1.0;
33 | }
34 | .spinner-button-updown .spinner-button-top,
35 | .spinner-button-updown .spinner-button-bottom {
36 | position: relative;
37 | display: block;
38 | width: 100%;
39 | height: 50%;
40 | }
41 | .spinner-button-updown .spinner-arrow-up,
42 | .spinner-button-updown .spinner-arrow-down {
43 | opacity: 1.0;
44 | filter: alpha(opacity=100);
45 | cursor: pointer;
46 | width: 16px;
47 | height: 16px;
48 | top: 50%;
49 | left: 50%;
50 | margin-top: -8px;
51 | margin-left: -8px;
52 | position: absolute;
53 | }
54 | .spinner-button-updown .spinner-button-top,
55 | .spinner-button-updown .spinner-button-bottom {
56 | cursor: pointer;
57 | opacity: 0.6;
58 | filter: alpha(opacity=60);
59 | }
60 | .spinner-button-updown .spinner-button-top:hover,
61 | .spinner-button-updown .spinner-button-bottom:hover {
62 | opacity: 1.0;
63 | filter: alpha(opacity=100);
64 | }
65 | .spinner-button-updown .spinner-arrow-up,
66 | .spinner-button-updown .spinner-arrow-down,
67 | .spinner-button-updown .spinner-arrow-up:hover,
68 | .spinner-button-updown .spinner-arrow-down:hover {
69 | background-color: transparent;
70 | }
71 | .spinner-arrow-hover {
72 | background-color: #eaf2ff;
73 | opacity: 1.0;
74 | filter: alpha(opacity=100);
75 | }
76 | .spinner-button-top:hover,
77 | .spinner-button-bottom:hover,
78 | .spinner-button-left:hover,
79 | .spinner-button-right:hover,
80 | .spinner-arrow-up:hover,
81 | .spinner-arrow-down:hover {
82 | opacity: 1.0;
83 | filter: alpha(opacity=100);
84 | background-color: #eaf2ff;
85 | }
86 | .textbox-disabled .spinner-button-top:hover,
87 | .textbox-disabled .spinner-button-bottom:hover,
88 | .textbox-disabled .spinner-button-left:hover,
89 | .textbox-disabled .spinner-button-right:hover,
90 | .textbox-icon-disabled .spinner-arrow-up:hover,
91 | .textbox-icon-disabled .spinner-arrow-down:hover {
92 | opacity: 0.6;
93 | filter: alpha(opacity=60);
94 | background-color: #E0ECFF;
95 | cursor: default;
96 | }
97 | .spinner .textbox-icon-disabled {
98 | opacity: 0.6;
99 | filter: alpha(opacity=60);
100 | }
101 | .spinner-arrow-up {
102 | background: url('images/spinner_arrows.png') no-repeat 1px center;
103 | background-color: #E0ECFF;
104 | }
105 | .spinner-arrow-down {
106 | background: url('images/spinner_arrows.png') no-repeat -15px center;
107 | background-color: #E0ECFF;
108 | }
109 | .spinner-button-up {
110 | background: url('images/spinner_arrows.png') no-repeat -32px center;
111 | }
112 | .spinner-button-down {
113 | background: url('images/spinner_arrows.png') no-repeat -48px center;
114 | }
115 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/textbox.css:
--------------------------------------------------------------------------------
1 | .textbox {
2 | position: relative;
3 | border: 1px solid #95B8E7;
4 | background-color: #fff;
5 | vertical-align: middle;
6 | display: inline-block;
7 | overflow: hidden;
8 | white-space: nowrap;
9 | margin: 0;
10 | padding: 0;
11 | -moz-border-radius: 5px 5px 5px 5px;
12 | -webkit-border-radius: 5px 5px 5px 5px;
13 | border-radius: 5px 5px 5px 5px;
14 | }
15 | .textbox .textbox-text {
16 | font-size: 14px;
17 | border: 0;
18 | margin: 0;
19 | padding: 0 4px;
20 | white-space: normal;
21 | vertical-align: top;
22 | outline-style: none;
23 | resize: none;
24 | -moz-border-radius: 5px 5px 5px 5px;
25 | -webkit-border-radius: 5px 5px 5px 5px;
26 | border-radius: 5px 5px 5px 5px;
27 | height: 28px;
28 | line-height: 28px;
29 | }
30 | .textbox textarea.textbox-text {
31 | line-height: normal;
32 | }
33 | .textbox .textbox-text::-ms-clear,
34 | .textbox .textbox-text::-ms-reveal {
35 | display: none;
36 | }
37 | .textbox textarea.textbox-text {
38 | white-space: pre-wrap;
39 | }
40 | .textbox .textbox-prompt {
41 | font-size: 14px;
42 | color: #aaa;
43 | }
44 | .textbox .textbox-bgicon {
45 | background-position: 3px center;
46 | padding-left: 21px;
47 | }
48 | .textbox .textbox-button,
49 | .textbox .textbox-button:hover {
50 | position: absolute;
51 | top: 0;
52 | padding: 0;
53 | vertical-align: top;
54 | -moz-border-radius: 0 0 0 0;
55 | -webkit-border-radius: 0 0 0 0;
56 | border-radius: 0 0 0 0;
57 | }
58 | .textbox .textbox-button-right,
59 | .textbox .textbox-button-right:hover {
60 | right: 0;
61 | border-width: 0 0 0 1px;
62 | }
63 | .textbox .textbox-button-left,
64 | .textbox .textbox-button-left:hover {
65 | left: 0;
66 | border-width: 0 1px 0 0;
67 | }
68 | .textbox .textbox-button-top,
69 | .textbox .textbox-button-top:hover {
70 | left: 0;
71 | border-width: 0 0 1px 0;
72 | }
73 | .textbox .textbox-button-bottom,
74 | .textbox .textbox-button-bottom:hover {
75 | top: auto;
76 | bottom: 0;
77 | left: 0;
78 | border-width: 1px 0 0 0;
79 | }
80 | .textbox-addon {
81 | position: absolute;
82 | top: 0;
83 | }
84 | .textbox-label {
85 | display: inline-block;
86 | width: 80px;
87 | height: 30px;
88 | line-height: 30px;
89 | vertical-align: middle;
90 | overflow: hidden;
91 | text-overflow: ellipsis;
92 | white-space: nowrap;
93 | margin: 0;
94 | padding-right: 5px;
95 | }
96 | .textbox-label-after {
97 | padding-left: 5px;
98 | padding-right: 0;
99 | }
100 | .textbox-label-top {
101 | display: block;
102 | width: auto;
103 | padding: 0;
104 | }
105 | .textbox-disabled,
106 | .textbox-label-disabled {
107 | opacity: 0.6;
108 | filter: alpha(opacity=60);
109 | }
110 | .textbox-icon {
111 | display: inline-block;
112 | width: 18px;
113 | height: 20px;
114 | overflow: hidden;
115 | vertical-align: top;
116 | background-position: center center;
117 | cursor: pointer;
118 | opacity: 0.6;
119 | filter: alpha(opacity=60);
120 | text-decoration: none;
121 | outline-style: none;
122 | }
123 | .textbox-icon-disabled,
124 | .textbox-icon-readonly {
125 | cursor: default;
126 | }
127 | .textbox-icon:hover {
128 | opacity: 1.0;
129 | filter: alpha(opacity=100);
130 | }
131 | .textbox-icon-disabled:hover {
132 | opacity: 0.6;
133 | filter: alpha(opacity=60);
134 | }
135 | .textbox-focused {
136 | border-color: #6b9cde;
137 | -moz-box-shadow: 0 0 3px 0 #95B8E7;
138 | -webkit-box-shadow: 0 0 3px 0 #95B8E7;
139 | box-shadow: 0 0 3px 0 #95B8E7;
140 | }
141 | .textbox-invalid {
142 | border-color: #ffa8a8;
143 | background-color: #fff3f3;
144 | }
145 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/layout.css:
--------------------------------------------------------------------------------
1 | .layout {
2 | position: relative;
3 | overflow: hidden;
4 | margin: 0;
5 | padding: 0;
6 | z-index: 0;
7 | }
8 | .layout-panel {
9 | position: absolute;
10 | overflow: hidden;
11 | }
12 | .layout-body {
13 | min-width: 1px;
14 | min-height: 1px;
15 | }
16 | .layout-panel-east,
17 | .layout-panel-west {
18 | z-index: 2;
19 | }
20 | .layout-panel-north,
21 | .layout-panel-south {
22 | z-index: 3;
23 | }
24 | .layout-expand {
25 | position: absolute;
26 | padding: 0px;
27 | font-size: 1px;
28 | cursor: pointer;
29 | z-index: 1;
30 | }
31 | .layout-expand .panel-header,
32 | .layout-expand .panel-body {
33 | background: transparent;
34 | filter: none;
35 | overflow: hidden;
36 | }
37 | .layout-expand .panel-header {
38 | border-bottom-width: 0px;
39 | }
40 | .layout-expand .panel-body {
41 | position: relative;
42 | }
43 | .layout-expand .panel-body .panel-icon {
44 | margin-top: 0;
45 | top: 0;
46 | left: 50%;
47 | margin-left: -8px;
48 | }
49 | .layout-expand-west .panel-header .panel-icon,
50 | .layout-expand-east .panel-header .panel-icon {
51 | display: none;
52 | }
53 | .layout-expand-title {
54 | position: absolute;
55 | top: 0;
56 | left: 21px;
57 | white-space: nowrap;
58 | word-wrap: normal;
59 | -webkit-transform: rotate(90deg);
60 | -webkit-transform-origin: 0 0;
61 | -moz-transform: rotate(90deg);
62 | -moz-transform-origin: 0 0;
63 | -o-transform: rotate(90deg);
64 | -o-transform-origin: 0 0;
65 | transform: rotate(90deg);
66 | transform-origin: 0 0;
67 | }
68 | .layout-expand-title-up {
69 | position: absolute;
70 | top: 0;
71 | left: 0;
72 | text-align: right;
73 | padding-left: 5px;
74 | white-space: nowrap;
75 | word-wrap: normal;
76 | -webkit-transform: rotate(-90deg);
77 | -webkit-transform-origin: 0 0;
78 | -moz-transform: rotate(-90deg);
79 | -moz-transform-origin: 0 0;
80 | -o-transform: rotate(-90deg);
81 | -o-transform-origin: 0 0;
82 | transform: rotate(-90deg);
83 | transform-origin: 0 0;
84 | }
85 | .layout-expand-with-icon {
86 | top: 18px;
87 | }
88 | .layout-expand .panel-body-noheader .layout-expand-title,
89 | .layout-expand .panel-body-noheader .panel-icon {
90 | top: 5px;
91 | }
92 | .layout-expand .panel-body-noheader .layout-expand-with-icon {
93 | top: 23px;
94 | }
95 | .layout-split-proxy-h,
96 | .layout-split-proxy-v {
97 | position: absolute;
98 | font-size: 1px;
99 | display: none;
100 | z-index: 5;
101 | }
102 | .layout-split-proxy-h {
103 | width: 5px;
104 | cursor: e-resize;
105 | }
106 | .layout-split-proxy-v {
107 | height: 5px;
108 | cursor: n-resize;
109 | }
110 | .layout-mask {
111 | position: absolute;
112 | background: #fafafa;
113 | filter: alpha(opacity=10);
114 | opacity: 0.10;
115 | z-index: 4;
116 | }
117 | .layout-button-up {
118 | background: url('images/layout_arrows.png') no-repeat -16px -16px;
119 | }
120 | .layout-button-down {
121 | background: url('images/layout_arrows.png') no-repeat -16px 0;
122 | }
123 | .layout-button-left {
124 | background: url('images/layout_arrows.png') no-repeat 0 0;
125 | }
126 | .layout-button-right {
127 | background: url('images/layout_arrows.png') no-repeat 0 -16px;
128 | }
129 | .layout-split-proxy-h,
130 | .layout-split-proxy-v {
131 | background-color: #aac5e7;
132 | }
133 | .layout-split-north {
134 | border-bottom: 5px solid #E6EEF8;
135 | }
136 | .layout-split-south {
137 | border-top: 5px solid #E6EEF8;
138 | }
139 | .layout-split-east {
140 | border-left: 5px solid #E6EEF8;
141 | }
142 | .layout-split-west {
143 | border-right: 5px solid #E6EEF8;
144 | }
145 | .layout-expand {
146 | background-color: #E0ECFF;
147 | }
148 | .layout-expand-over {
149 | background-color: #E0ECFF;
150 | }
151 |
--------------------------------------------------------------------------------
/parser/SmokeDetectorParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class SmokeDetectorParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'SmokeDetector_SmokeSensor': SmokeDetectorSmokeSensorParser
12 | }
13 | }
14 | }
15 | SmokeDetectorParser.modelName = ['smoke', 'sensor_smoke'];
16 | module.exports = SmokeDetectorParser;
17 |
18 | class SmokeDetectorSmokeSensorParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | return this.Accessory.Categories.SENSOR;
25 | }
26 |
27 | getAccessoryInformation(deviceSid) {
28 | return {
29 | 'Manufacturer': 'Aqara',
30 | 'Model': 'Smoke Detector',
31 | 'SerialNumber': deviceSid
32 | };
33 | }
34 |
35 | getServices(jsonObj, accessoryName) {
36 | var that = this;
37 | var result = [];
38 |
39 | var service = new that.Service.SmokeSensor(accessoryName);
40 | service.getCharacteristic(that.Characteristic.SmokeDetected);
41 | result.push(service);
42 |
43 | var batteryService = new that.Service.BatteryService(accessoryName);
44 | batteryService.getCharacteristic(that.Characteristic.StatusLowBattery);
45 | batteryService.getCharacteristic(that.Characteristic.BatteryLevel);
46 | batteryService.getCharacteristic(that.Characteristic.ChargingState);
47 | result.push(batteryService);
48 |
49 | return result;
50 | }
51 |
52 | parserAccessories(jsonObj) {
53 | var that = this;
54 | var deviceSid = jsonObj['sid'];
55 | var uuid = that.getAccessoryUUID(deviceSid);
56 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
57 | if(accessory) {
58 | var service = accessory.getService(that.Service.SmokeSensor);
59 | var smokeDetectedCharacteristic = service.getCharacteristic(that.Characteristic.SmokeDetected);
60 | var value = that.getSmokeDetectedCharacteristicValue(jsonObj, null);
61 | if(null != value) {
62 | smokeDetectedCharacteristic.updateValue(value ? that.Characteristic.SmokeDetected.SMOKE_DETECTED : that.Characteristic.SmokeDetected.SMOKE_NOT_DETECTED);
63 | }
64 |
65 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
66 | if (smokeDetectedCharacteristic.listeners('get').length == 0) {
67 | smokeDetectedCharacteristic.on("get", function(callback) {
68 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
69 | that.platform.sendReadCommand(deviceSid, command).then(result => {
70 | var value = that.getSmokeDetectedCharacteristicValue(result, null);
71 | if(null != value) {
72 | callback(null, value ? that.Characteristic.SmokeDetected.SMOKE_DETECTED : that.Characteristic.SmokeDetected.SMOKE_NOT_DETECTED);
73 | } else {
74 | callback(new Error('get value fail: ' + result));
75 | }
76 | }).catch(function(err) {
77 | that.platform.log.error(err);
78 | callback(err);
79 | });
80 | });
81 | }
82 | }
83 |
84 | that.parserBatteryService(accessory, jsonObj);
85 | }
86 | }
87 |
88 | getSmokeDetectedCharacteristicValue(jsonObj, defaultValue) {
89 | var value = this.getValueFrJsonObjData(jsonObj, 'alarm');
90 | if(value === '1' || value === '2') {
91 | return true;
92 | } else if(value === '0') {
93 | return false;
94 | } else {
95 | return false;
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/parser/NatgasDetectorParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class NatgasDetectorParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'NatgasDetector_SmokeSensor': NatgasDetectorSmokeSensorParser
12 | }
13 | }
14 | }
15 | NatgasDetectorParser.modelName = ['natgas', 'sensor_natgas'];
16 | module.exports = NatgasDetectorParser;
17 |
18 | class NatgasDetectorSmokeSensorParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | return this.Accessory.Categories.SENSOR;
25 | }
26 |
27 | getAccessoryInformation(deviceSid) {
28 | return {
29 | 'Manufacturer': 'Aqara',
30 | 'Model': 'Natgas Detector',
31 | 'SerialNumber': deviceSid
32 | };
33 | }
34 |
35 | getServices(jsonObj, accessoryName) {
36 | var that = this;
37 | var result = [];
38 |
39 | var service = new that.Service.SmokeSensor(accessoryName);
40 | service.getCharacteristic(that.Characteristic.SmokeDetected);
41 | result.push(service);
42 |
43 | var batteryService = new that.Service.BatteryService(accessoryName);
44 | batteryService.getCharacteristic(that.Characteristic.StatusLowBattery);
45 | batteryService.getCharacteristic(that.Characteristic.BatteryLevel);
46 | batteryService.getCharacteristic(that.Characteristic.ChargingState);
47 | result.push(batteryService);
48 |
49 | return result;
50 | }
51 |
52 | parserAccessories(jsonObj) {
53 | var that = this;
54 | var deviceSid = jsonObj['sid'];
55 | var uuid = that.getAccessoryUUID(deviceSid);
56 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
57 | if(accessory) {
58 | var service = accessory.getService(that.Service.SmokeSensor);
59 | var smokeDetectedCharacteristic = service.getCharacteristic(that.Characteristic.SmokeDetected);
60 | var value = that.getSmokeDetectedCharacteristicValue(jsonObj, null);
61 | if(null != value) {
62 | smokeDetectedCharacteristic.updateValue(value ? that.Characteristic.SmokeDetected.SMOKE_DETECTED : that.Characteristic.SmokeDetected.SMOKE_NOT_DETECTED);
63 | }
64 |
65 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
66 | if (smokeDetectedCharacteristic.listeners('get').length == 0) {
67 | smokeDetectedCharacteristic.on("get", function(callback) {
68 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
69 | that.platform.sendReadCommand(deviceSid, command).then(result => {
70 | var value = that.getSmokeDetectedCharacteristicValue(result, null);
71 | if(null != value) {
72 | callback(null, value ? that.Characteristic.SmokeDetected.SMOKE_DETECTED : that.Characteristic.SmokeDetected.SMOKE_NOT_DETECTED);
73 | } else {
74 | callback(new Error('get value fail: ' + result));
75 | }
76 | }).catch(function(err) {
77 | that.platform.log.error(err);
78 | callback(err);
79 | });
80 | });
81 | }
82 | }
83 |
84 | that.parserBatteryService(accessory, jsonObj);
85 | }
86 | }
87 |
88 | getSmokeDetectedCharacteristicValue(jsonObj, defaultValue) {
89 | var value = this.getValueFrJsonObjData(jsonObj, 'alarm');
90 | if(value === '1' || value === '2') {
91 | return true;
92 | } else if(value === '0') {
93 | return false;
94 | } else {
95 | return false;
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/parser/MotionSensorParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class MotionSensorParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'MotionSensor_MotionSensor': MotionSensorMotionSensorParser
12 | }
13 | }
14 | }
15 | MotionSensorParser.modelName = ['motion'];
16 | module.exports = MotionSensorParser;
17 |
18 | class MotionSensorMotionSensorParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | return this.Accessory.Categories.SENSOR;
25 | }
26 |
27 | getAccessoryInformation(deviceSid) {
28 | return {
29 | 'Manufacturer': 'Aqara',
30 | 'Model': 'Motion Sensor',
31 | 'SerialNumber': deviceSid
32 | };
33 | }
34 |
35 | getServices(jsonObj, accessoryName) {
36 | var that = this;
37 | var result = [];
38 |
39 | var service = new that.Service.MotionSensor(accessoryName);
40 | service.getCharacteristic(that.Characteristic.MotionDetected);
41 | result.push(service);
42 |
43 | var batteryService = new that.Service.BatteryService(accessoryName);
44 | batteryService.getCharacteristic(that.Characteristic.StatusLowBattery);
45 | batteryService.getCharacteristic(that.Characteristic.BatteryLevel);
46 | batteryService.getCharacteristic(that.Characteristic.ChargingState);
47 | result.push(batteryService);
48 |
49 | return result;
50 | }
51 |
52 | parserAccessories(jsonObj) {
53 | var that = this;
54 | var deviceSid = jsonObj['sid'];
55 | var uuid = that.getAccessoryUUID(deviceSid);
56 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
57 | if(accessory) {
58 | var service = accessory.getService(that.Service.MotionSensor);
59 | var motionDetectedCharacteristic = service.getCharacteristic(that.Characteristic.MotionDetected);
60 | var value = that.getMotionDetectedCharacteristicValue(jsonObj, null);
61 | if(null != value) {
62 | motionDetectedCharacteristic.updateValue(value);
63 | }
64 |
65 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
66 | if (motionDetectedCharacteristic.listeners('get').length == 0) {
67 | motionDetectedCharacteristic.on("get", function(callback) {
68 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
69 | that.platform.sendReadCommand(deviceSid, command).then(result => {
70 | var value = that.getMotionDetectedCharacteristicValue(result, null);
71 | if(null != value) {
72 | callback(null, value);
73 | } else {
74 | callback(new Error('get value fail: ' + result));
75 | }
76 | }).catch(function(err) {
77 | that.platform.log.error(err);
78 | callback(err);
79 | });
80 | });
81 | }
82 | }
83 |
84 | that.parserBatteryService(accessory, jsonObj);
85 | }
86 | }
87 |
88 | getMotionDetectedCharacteristicValue(jsonObj, defaultValue) {
89 | var value = null;
90 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(jsonObj['sid']));
91 | if(1 == proto_version_prefix) {
92 | value = this.getValueFrJsonObjData1(jsonObj, 'status');
93 | } else if(2 == proto_version_prefix) {
94 | value = this.getValueFrJsonObjData2(jsonObj, 'motion_status');
95 | } else {
96 | }
97 |
98 | return (null != value) ? (value === 'motion') : false;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/tree.css:
--------------------------------------------------------------------------------
1 | .tree {
2 | margin: 0;
3 | padding: 0;
4 | list-style-type: none;
5 | }
6 | .tree li {
7 | white-space: nowrap;
8 | }
9 | .tree li ul {
10 | list-style-type: none;
11 | margin: 0;
12 | padding: 0;
13 | }
14 | .tree-node {
15 | height: 26px;
16 | white-space: nowrap;
17 | cursor: pointer;
18 | }
19 | .tree-hit {
20 | cursor: pointer;
21 | }
22 | .tree-expanded,
23 | .tree-collapsed,
24 | .tree-folder,
25 | .tree-file,
26 | .tree-checkbox,
27 | .tree-indent {
28 | display: inline-block;
29 | width: 16px;
30 | height: 18px;
31 | margin: 4px 0;
32 | vertical-align: middle;
33 | overflow: hidden;
34 | }
35 | .tree-expanded {
36 | background: url('images/tree_icons.png') no-repeat -18px 0px;
37 | }
38 | .tree-expanded-hover {
39 | background: url('images/tree_icons.png') no-repeat -50px 0px;
40 | }
41 | .tree-collapsed {
42 | background: url('images/tree_icons.png') no-repeat 0px 0px;
43 | }
44 | .tree-collapsed-hover {
45 | background: url('images/tree_icons.png') no-repeat -32px 0px;
46 | }
47 | .tree-lines .tree-expanded,
48 | .tree-lines .tree-root-first .tree-expanded {
49 | background: url('images/tree_icons.png') no-repeat -144px 0;
50 | }
51 | .tree-lines .tree-collapsed,
52 | .tree-lines .tree-root-first .tree-collapsed {
53 | background: url('images/tree_icons.png') no-repeat -128px 0;
54 | }
55 | .tree-lines .tree-node-last .tree-expanded,
56 | .tree-lines .tree-root-one .tree-expanded {
57 | background: url('images/tree_icons.png') no-repeat -80px 0;
58 | }
59 | .tree-lines .tree-node-last .tree-collapsed,
60 | .tree-lines .tree-root-one .tree-collapsed {
61 | background: url('images/tree_icons.png') no-repeat -64px 0;
62 | }
63 | .tree-line {
64 | background: url('images/tree_icons.png') no-repeat -176px 0;
65 | }
66 | .tree-join {
67 | background: url('images/tree_icons.png') no-repeat -192px 0;
68 | }
69 | .tree-joinbottom {
70 | background: url('images/tree_icons.png') no-repeat -160px 0;
71 | }
72 | .tree-folder {
73 | background: url('images/tree_icons.png') no-repeat -208px 0;
74 | }
75 | .tree-folder-open {
76 | background: url('images/tree_icons.png') no-repeat -224px 0;
77 | }
78 | .tree-file {
79 | background: url('images/tree_icons.png') no-repeat -240px 0;
80 | }
81 | .tree-loading {
82 | background: url('images/loading.gif') no-repeat center center;
83 | }
84 | .tree-checkbox0 {
85 | background: url('images/tree_icons.png') no-repeat -208px -18px;
86 | }
87 | .tree-checkbox1 {
88 | background: url('images/tree_icons.png') no-repeat -224px -18px;
89 | }
90 | .tree-checkbox2 {
91 | background: url('images/tree_icons.png') no-repeat -240px -18px;
92 | }
93 | .tree-title {
94 | font-size: 14px;
95 | display: inline-block;
96 | text-decoration: none;
97 | vertical-align: middle;
98 | white-space: nowrap;
99 | padding: 0 2px;
100 | margin: 4px 0;
101 | height: 18px;
102 | line-height: 18px;
103 | }
104 | .tree-node-proxy {
105 | font-size: 14px;
106 | line-height: 20px;
107 | padding: 0 2px 0 20px;
108 | border-width: 1px;
109 | border-style: solid;
110 | z-index: 9900000;
111 | }
112 | .tree-dnd-icon {
113 | display: inline-block;
114 | position: absolute;
115 | width: 16px;
116 | height: 18px;
117 | left: 2px;
118 | top: 50%;
119 | margin-top: -9px;
120 | }
121 | .tree-dnd-yes {
122 | background: url('images/tree_icons.png') no-repeat -256px 0;
123 | }
124 | .tree-dnd-no {
125 | background: url('images/tree_icons.png') no-repeat -256px -18px;
126 | }
127 | .tree-node-top {
128 | border-top: 1px dotted red;
129 | }
130 | .tree-node-bottom {
131 | border-bottom: 1px dotted red;
132 | }
133 | .tree-node-append .tree-title {
134 | border: 1px dotted red;
135 | }
136 | .tree-editor {
137 | border: 1px solid #95B8E7;
138 | font-size: 14px;
139 | height: 26px;
140 | line-height: 26px;
141 | padding: 0 4px;
142 | margin: 0;
143 | width: 80px;
144 | outline-style: none;
145 | vertical-align: middle;
146 | position: absolute;
147 | top: 0;
148 | }
149 | .tree-node-proxy {
150 | background-color: #ffffff;
151 | color: #000000;
152 | border-color: #95B8E7;
153 | }
154 | .tree-node-hover {
155 | background: #eaf2ff;
156 | color: #000000;
157 | }
158 | .tree-node-selected {
159 | background: #ffe48d;
160 | color: #000000;
161 | }
162 | .tree-node-hidden {
163 | display: none;
164 | }
165 |
--------------------------------------------------------------------------------
/lib/ParseUtil.js:
--------------------------------------------------------------------------------
1 | var fs = require("fs");
2 | var path = require('path');
3 |
4 | class ParseUtil {
5 | constructor(platform) {
6 | this.platform = platform;
7 | this.parsers = {};
8 | this.gatewayModels = [];
9 |
10 | this.loadParser();
11 | }
12 |
13 | loadParser() {
14 | var that = this;
15 | var parsersPath = path.resolve(__dirname, './../parser/');
16 | that.platform.log.debug('loading parsers from: ' + parsersPath);
17 | fs.readdir(parsersPath, function (err, files) {
18 | if (err) {
19 | return;
20 | }
21 | files.forEach(function (filename) {
22 | if(filename == null || filename == '') {
23 | return;
24 | }
25 | if('.js' != filename.substring(filename.lastIndexOf('.'), filename.length)) {
26 | return;
27 | }
28 | if('AccessoryParser.js' == filename) {
29 | return;
30 | }
31 | if('DeviceParser.js' == filename) {
32 | return;
33 | }
34 | // that.platform.log.debug(filename);
35 |
36 | var parserPath = path.join(parsersPath, filename);
37 | try {
38 | var parserFile = require(parserPath);
39 | var parserModel = parserFile && parserFile.modelName;
40 | if (!parserModel) {
41 | return;
42 | }
43 |
44 | var parser = new parserFile(that.platform);
45 | if (parserModel instanceof Array) {
46 | parserModel.forEach(function (model) {
47 | that.parsers[model] = parser;
48 | if(parserFile.isGateway) {
49 | that.gatewayModels.push(model);
50 | }
51 | // that.platform.log.debug(model);
52 | });
53 | } else {
54 | that.parsers[parserModel] = parser;
55 | if(parserFile.isGateway) {
56 | that.gatewayModels.push(parserModel);
57 | }
58 | // that.platform.log.debug(parserModel);
59 | }
60 | } catch (error) {
61 | that.platform.log.error(error);
62 | }
63 | });
64 | });
65 | }
66 |
67 | isGatewayModel(modelName) {
68 | if (this.gatewayModels.indexOf(modelName) > -1) {
69 | return true;
70 | } else {
71 | return false;
72 | }
73 | }
74 |
75 | getByModel(model) {
76 | return (model in this.parsers) ? this.parsers[model]: null;
77 | }
78 |
79 | getByModelName(model) {
80 | function getFnName(fn){
81 | return typeof fn !== "function" ?
82 | undefined:
83 | fn.name ||
84 | /function (.+?)\(/.exec(fn + "")[1];
85 | }
86 | var parse = this.getByModel(model);
87 | if(parse) {
88 | return getFnName(parse.constructor).replace("Parser", "");
89 | } else {
90 | return "";
91 | }
92 | }
93 |
94 | getCreateAccessories(jsonObj) {
95 | var result = [];
96 |
97 | var model = jsonObj['model'];
98 | var parser = this.getByModel(model);
99 | if(parser) {
100 | result = parser.getCreateAccessories(jsonObj);
101 | }
102 |
103 | return result;
104 | }
105 |
106 | parserAccessories(jsonObj) {
107 | var result = [];
108 |
109 | var model = jsonObj['model'];
110 | var parser = this.getByModel(model);
111 | if(parser) {
112 | result = parser.parserAccessories(jsonObj);
113 | }
114 |
115 | return result;
116 | }
117 |
118 | getAccessoriesUUID(sid, deviceModel) {
119 | var result = [];
120 |
121 | var parser = this.getByModel(deviceModel);
122 | if(parser) {
123 | result = parser.getAccessoriesUUID(sid);
124 | }
125 |
126 | return result;
127 | }
128 | }
129 |
130 | module.exports = ParseUtil;
--------------------------------------------------------------------------------
/parser/ContactSensorParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class ContactSensorParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'ContactSensor_ContactSensor': ContactSensorContactSensorParser
12 | }
13 | }
14 | }
15 | ContactSensorParser.modelName = ['magnet', 'sensor_magnet'];
16 | module.exports = ContactSensorParser;
17 |
18 | class ContactSensorContactSensorParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | return this.Accessory.Categories.SENSOR;
25 | }
26 |
27 | getAccessoryInformation(deviceSid) {
28 | return {
29 | 'Manufacturer': 'Aqara',
30 | 'Model': 'Contact Sensor',
31 | 'SerialNumber': deviceSid
32 | };
33 | }
34 |
35 | getServices(jsonObj, accessoryName) {
36 | var that = this;
37 | var result = [];
38 |
39 | var service = new that.Service.ContactSensor(accessoryName);
40 | service.getCharacteristic(that.Characteristic.ContactSensorState);
41 | result.push(service);
42 |
43 | var batteryService = new that.Service.BatteryService(accessoryName);
44 | batteryService.getCharacteristic(that.Characteristic.StatusLowBattery);
45 | batteryService.getCharacteristic(that.Characteristic.BatteryLevel);
46 | batteryService.getCharacteristic(that.Characteristic.ChargingState);
47 | result.push(batteryService);
48 |
49 | return result;
50 | }
51 |
52 | parserAccessories(jsonObj) {
53 | var that = this;
54 | var deviceSid = jsonObj['sid'];
55 | var uuid = that.getAccessoryUUID(deviceSid);
56 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
57 | if(accessory) {
58 | var service = accessory.getService(that.Service.ContactSensor);
59 | var contactSensorStateCharacteristic = service.getCharacteristic(that.Characteristic.ContactSensorState);
60 | var value = that.getContactSensorStateCharacteristicValue(jsonObj, null);
61 | if(null != value) {
62 | contactSensorStateCharacteristic.updateValue(value ? that.Characteristic.ContactSensorState.CONTACT_DETECTED : that.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED);
63 | }
64 |
65 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
66 | if (contactSensorStateCharacteristic.listeners('get').length == 0) {
67 | contactSensorStateCharacteristic.on("get", function(callback) {
68 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
69 | that.platform.sendReadCommand(deviceSid, command).then(result => {
70 | var value = that.getContactSensorStateCharacteristicValue(result, null);
71 | if(null != value) {
72 | callback(null, value ? that.Characteristic.ContactSensorState.CONTACT_DETECTED : that.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED);
73 | } else {
74 | callback(new Error('get value fail: ' + result));
75 | }
76 | }).catch(function(err) {
77 | that.platform.log.error(err);
78 | callback(err);
79 | });
80 | });
81 | }
82 | }
83 |
84 | that.parserBatteryService(accessory, jsonObj);
85 | }
86 | }
87 |
88 | getContactSensorStateCharacteristicValue(jsonObj, defaultValue) {
89 | var value = null;
90 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(jsonObj['sid']));
91 | if(1 == proto_version_prefix) {
92 | value = this.getValueFrJsonObjData1(jsonObj, 'status');
93 | } else if(2 == proto_version_prefix) {
94 | value = this.getValueFrJsonObjData2(jsonObj, 'window_status');
95 | } else {
96 | }
97 |
98 | return (null != value) ? (value === 'close') : defaultValue;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/parser/ContactSensor2Parser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class ContactSensor2Parser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'ContactSensor2_ContactSensor': ContactSensor2ContactSensorParser
12 | }
13 | }
14 | }
15 | ContactSensor2Parser.modelName = ['sensor_magnet.aq2'];
16 | module.exports = ContactSensor2Parser;
17 |
18 | class ContactSensor2ContactSensorParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | return this.Accessory.Categories.SENSOR;
25 | }
26 |
27 | getAccessoryInformation(deviceSid) {
28 | return {
29 | 'Manufacturer': 'Aqara',
30 | 'Model': 'Contact Sensor 2',
31 | 'SerialNumber': deviceSid
32 | };
33 | }
34 |
35 | getServices(jsonObj, accessoryName) {
36 | var that = this;
37 | var result = [];
38 |
39 | var service = new that.Service.ContactSensor(accessoryName);
40 | service.getCharacteristic(that.Characteristic.ContactSensorState);
41 | result.push(service);
42 |
43 | var batteryService = new that.Service.BatteryService(accessoryName);
44 | batteryService.getCharacteristic(that.Characteristic.StatusLowBattery);
45 | batteryService.getCharacteristic(that.Characteristic.BatteryLevel);
46 | batteryService.getCharacteristic(that.Characteristic.ChargingState);
47 | result.push(batteryService);
48 |
49 | return result;
50 | }
51 |
52 | parserAccessories(jsonObj) {
53 | var that = this;
54 | var deviceSid = jsonObj['sid'];
55 | var uuid = that.getAccessoryUUID(deviceSid);
56 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
57 | if(accessory) {
58 | var service = accessory.getService(that.Service.ContactSensor);
59 | var contactSensorStateCharacteristic = service.getCharacteristic(that.Characteristic.ContactSensorState);
60 | var value = that.getContactSensorStateCharacteristicValue(jsonObj, null);
61 | if(null != value) {
62 | contactSensorStateCharacteristic.updateValue(value ? that.Characteristic.ContactSensorState.CONTACT_DETECTED : that.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED);
63 | }
64 |
65 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
66 | if (contactSensorStateCharacteristic.listeners('get').length == 0) {
67 | contactSensorStateCharacteristic.on("get", function(callback) {
68 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
69 | that.platform.sendReadCommand(deviceSid, command).then(result => {
70 | var value = that.getContactSensorStateCharacteristicValue(result, null);
71 | if(null != value) {
72 | callback(null, value ? that.Characteristic.ContactSensorState.CONTACT_DETECTED : that.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED);
73 | } else {
74 | callback(new Error('get value fail: ' + result));
75 | }
76 | }).catch(function(err) {
77 | that.platform.log.error(err);
78 | callback(err);
79 | });
80 | });
81 | }
82 | }
83 |
84 | that.parserBatteryService(accessory, jsonObj);
85 | }
86 | }
87 |
88 | getContactSensorStateCharacteristicValue(jsonObj, defaultValue) {
89 | var value = null;
90 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(jsonObj['sid']));
91 | if(1 == proto_version_prefix) {
92 | value = this.getValueFrJsonObjData1(jsonObj, 'status');
93 | } else if(2 == proto_version_prefix) {
94 | value = this.getValueFrJsonObjData2(jsonObj, 'window_status');
95 | } else {
96 | }
97 |
98 | return (null != value) ? (value === 'close') : defaultValue;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/parser/WaterDetectorParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class WaterDetectorParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'WaterDetector_LeakSensor': WaterDetectorLeakSensorParser
12 | }
13 | }
14 | }
15 | WaterDetectorParser.modelName = ['sensor_wleak.aq1'];
16 | module.exports = WaterDetectorParser;
17 |
18 | class WaterDetectorLeakSensorParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | return this.Accessory.Categories.SENSOR;
25 | }
26 |
27 | getAccessoryInformation(deviceSid) {
28 | return {
29 | 'Manufacturer': 'Aqara',
30 | 'Model': 'Water Detector',
31 | 'SerialNumber': deviceSid
32 | };
33 | }
34 |
35 | getServices(jsonObj, accessoryName) {
36 | var that = this;
37 | var result = [];
38 |
39 | var service = new that.Service.LeakSensor(accessoryName);
40 | service.getCharacteristic(that.Characteristic.LeakDetected);
41 | result.push(service);
42 |
43 | var batteryService = new that.Service.BatteryService(accessoryName);
44 | batteryService.getCharacteristic(that.Characteristic.StatusLowBattery);
45 | batteryService.getCharacteristic(that.Characteristic.BatteryLevel);
46 | batteryService.getCharacteristic(that.Characteristic.ChargingState);
47 | result.push(batteryService);
48 |
49 | return result;
50 | }
51 |
52 | parserAccessories(jsonObj) {
53 | var that = this;
54 | var deviceSid = jsonObj['sid'];
55 | var uuid = that.getAccessoryUUID(deviceSid);
56 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
57 | if(accessory) {
58 | var service = accessory.getService(that.Service.LeakSensor);
59 | var leakDetectedCharacteristic = service.getCharacteristic(that.Characteristic.LeakDetected);
60 | var value = that.getLeakDetectedCharacteristicValue(jsonObj, null);
61 | if(null != value) {
62 | leakDetectedCharacteristic.updateValue(value ? that.Characteristic.LeakDetected.LEAK_DETECTED : that.Characteristic.LeakDetected.LEAK_NOT_DETECTED);
63 | }
64 |
65 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
66 | if (leakDetectedCharacteristic.listeners('get').length == 0) {
67 | leakDetectedCharacteristic.on("get", function(callback) {
68 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
69 | that.platform.sendReadCommand(deviceSid, command).then(result => {
70 | var value = that.getLeakDetectedCharacteristicValue(result, false);
71 | if(null != value) {
72 | callback(null, value ? that.Characteristic.LeakDetected.LEAK_DETECTED : that.Characteristic.LeakDetected.LEAK_NOT_DETECTED);
73 | } else {
74 | callback(new Error('get value fail: ' + result));
75 | }
76 | }).catch(function(err) {
77 | that.platform.log.error(err);
78 | callback(err);
79 | });
80 | });
81 | }
82 | }
83 |
84 | that.parserBatteryService(accessory, jsonObj);
85 | }
86 | }
87 |
88 | getLeakDetectedCharacteristicValue(jsonObj, defaultValue) {
89 | var value = null;
90 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(jsonObj['sid']));
91 | if(1 == proto_version_prefix) {
92 | value = this.getValueFrJsonObjData1(jsonObj, 'status');
93 | } else if(2 == proto_version_prefix) {
94 | value = this.getValueFrJsonObjData2(jsonObj, 'wleak_status');
95 | } else {
96 | }
97 |
98 | if(value === 'leak') {
99 | return true;
100 | } else if(value === 'no_leak') {
101 | return false;
102 | } else {
103 | return false;
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/manage/css/device_icon.css:
--------------------------------------------------------------------------------
1 | .icon-device-Gateway {
2 | background:url('../images/deviceIcons/Gateway.png') no-repeat center center;
3 | background-size: 16px 16px;
4 | }
5 |
6 | .icon-device-ContactSensor {
7 | background:url('../images/deviceIcons/ContactSensor.png') no-repeat center center;
8 | background-size: 16px 16px;
9 | }
10 |
11 | .icon-device-MotionSensor {
12 | background:url('../images/deviceIcons/MotionSensor.png') no-repeat center center;
13 | background-size: 16px 16px;
14 | }
15 |
16 | .icon-device-Button {
17 | background:url('../images/deviceIcons/Button.png') no-repeat center center;
18 | background-size: 16px 16px;
19 | }
20 |
21 | .icon-device-TemperatureAndHumiditySensor {
22 | background:url('../images/deviceIcons/TemperatureAndHumiditySensor.png') no-repeat center center;
23 | background-size: 16px 16px;
24 | }
25 |
26 | .icon-device-SingleSwitch {
27 | background:url('../images/deviceIcons/SingleSwitch.png') no-repeat center center;
28 | background-size: 16px 16px;
29 | }
30 |
31 | .icon-device-DuplexSwitch {
32 | background:url('../images/deviceIcons/DuplexSwitch.png') no-repeat center center;
33 | background-size: 16px 16px;
34 | }
35 |
36 | .icon-device-SingleSwitchLN {
37 | background:url('../images/deviceIcons/SingleSwitchLN.png') no-repeat center center;
38 | background-size: 16px 16px;
39 | }
40 |
41 | .icon-device-DuplexSwitchLN {
42 | background:url('../images/deviceIcons/DuplexSwitchLN.png') no-repeat center center;
43 | background-size: 16px 16px;
44 | }
45 |
46 | .icon-device-SingleButton86 {
47 | background:url('../images/deviceIcons/SingleButton86.png') no-repeat center center;
48 | background-size: 16px 16px;
49 | }
50 |
51 | .icon-device-DuplexButton86 {
52 | background:url('../images/deviceIcons/DuplexButton86.png') no-repeat center center;
53 | background-size: 16px 16px;
54 | }
55 |
56 | .icon-device-PlugBase {
57 | background:url('../images/deviceIcons/PlugBase.png') no-repeat center center;
58 | background-size: 16px 16px;
59 | }
60 |
61 | .icon-device-PlugBase86 {
62 | background:url('../images/deviceIcons/PlugBase86.png') no-repeat center center;
63 | background-size: 16px 16px;
64 | }
65 |
66 | .icon-device-MagicSquare {
67 | background:url('../images/deviceIcons/MagicSquare.png') no-repeat center center;
68 | background-size: 16px 16px;
69 | }
70 |
71 | .icon-device-SmokeDetector {
72 | background:url('../images/deviceIcons/SmokeDetector.png') no-repeat center center;
73 | background-size: 16px 16px;
74 | }
75 |
76 | .icon-device-NatgasDetector {
77 | background:url('../images/deviceIcons/NatgasDetector.png') no-repeat center center;
78 | background-size: 16px 16px;
79 | }
80 |
81 | .icon-device-ElectricCurtain {
82 | background:url('../images/deviceIcons/ElectricCurtain.png') no-repeat center center;
83 | background-size: 16px 16px;
84 | }
85 |
86 | .icon-device-ContactSensor2 {
87 | background:url('../images/deviceIcons/ContactSensor2.png') no-repeat center center;
88 | background-size: 16px 16px;
89 | }
90 |
91 | .icon-device-MotionSensor2 {
92 | background:url('../images/deviceIcons/MotionSensor2.png') no-repeat center center;
93 | background-size: 16px 16px;
94 | }
95 |
96 | .icon-device-Button2 {
97 | background:url('../images/deviceIcons/Button2.png') no-repeat center center;
98 | background-size: 16px 16px;
99 | }
100 |
101 | .icon-device-TemperatureAndHumiditySensor2 {
102 | background:url('../images/deviceIcons/TemperatureAndHumiditySensor2.png') no-repeat center center;
103 | background-size: 16px 16px;
104 | }
105 |
106 | .icon-device-WaterDetector {
107 | background:url('../images/deviceIcons/WaterDetector.png') no-repeat center center;
108 | background-size: 16px 16px;
109 | }
110 |
111 | .icon-device-Lock {
112 | background:url('../images/deviceIcons/Lock.png') no-repeat center center;
113 | background-size: 16px 16px;
114 | }
115 |
116 | .icon-device-AcPartner {
117 | background:url('../images/deviceIcons/AcPartner.png') no-repeat center center;
118 | background-size: 16px 16px;
119 | }
120 |
121 | .icon-device-Button3 {
122 | background:url('../images/deviceIcons/Button3.png') no-repeat center center;
123 | background-size: 16px 16px;
124 | }
125 |
126 | .icon-device-DuplexButton862 {
127 | background:url('../images/deviceIcons/DuplexButton862.png') no-repeat center center;
128 | background-size: 16px 16px;
129 | }
130 |
131 | .icon-device-VibrationSensor {
132 | background:url('../images/deviceIcons/Vibration.png') no-repeat center center;
133 | background-size: 16px 16px;
134 | }
--------------------------------------------------------------------------------
/manage/easyui/themes/default/calendar.css:
--------------------------------------------------------------------------------
1 | .calendar {
2 | border-width: 1px;
3 | border-style: solid;
4 | padding: 1px;
5 | overflow: hidden;
6 | }
7 | .calendar table {
8 | table-layout: fixed;
9 | border-collapse: separate;
10 | font-size: 14px;
11 | width: 100%;
12 | height: 100%;
13 | }
14 | .calendar table td,
15 | .calendar table th {
16 | font-size: 14px;
17 | }
18 | .calendar-noborder {
19 | border: 0;
20 | }
21 | .calendar-header {
22 | position: relative;
23 | height: 28px;
24 | }
25 | .calendar-title {
26 | text-align: center;
27 | height: 28px;
28 | }
29 | .calendar-title span {
30 | position: relative;
31 | display: inline-block;
32 | top: 0px;
33 | padding: 0 3px;
34 | height: 28px;
35 | line-height: 28px;
36 | font-size: 14px;
37 | cursor: pointer;
38 | -moz-border-radius: 5px 5px 5px 5px;
39 | -webkit-border-radius: 5px 5px 5px 5px;
40 | border-radius: 5px 5px 5px 5px;
41 | }
42 | .calendar-prevmonth,
43 | .calendar-nextmonth,
44 | .calendar-prevyear,
45 | .calendar-nextyear {
46 | position: absolute;
47 | top: 50%;
48 | margin-top: -8px;
49 | width: 16px;
50 | height: 16px;
51 | cursor: pointer;
52 | font-size: 1px;
53 | -moz-border-radius: 5px 5px 5px 5px;
54 | -webkit-border-radius: 5px 5px 5px 5px;
55 | border-radius: 5px 5px 5px 5px;
56 | }
57 | .calendar-prevmonth {
58 | left: 20px;
59 | background: url('images/calendar_arrows.png') no-repeat -16px 0;
60 | }
61 | .calendar-nextmonth {
62 | right: 20px;
63 | background: url('images/calendar_arrows.png') no-repeat -32px 0;
64 | }
65 | .calendar-prevyear {
66 | left: 3px;
67 | background: url('images/calendar_arrows.png') no-repeat 0px 0;
68 | }
69 | .calendar-nextyear {
70 | right: 3px;
71 | background: url('images/calendar_arrows.png') no-repeat -48px 0;
72 | }
73 | .calendar-body {
74 | position: relative;
75 | }
76 | .calendar-body th,
77 | .calendar-body td {
78 | text-align: center;
79 | }
80 | .calendar-day {
81 | border: 0;
82 | padding: 1px;
83 | cursor: pointer;
84 | -moz-border-radius: 5px 5px 5px 5px;
85 | -webkit-border-radius: 5px 5px 5px 5px;
86 | border-radius: 5px 5px 5px 5px;
87 | }
88 | .calendar-other-month {
89 | opacity: 0.3;
90 | filter: alpha(opacity=30);
91 | }
92 | .calendar-disabled {
93 | opacity: 0.6;
94 | filter: alpha(opacity=60);
95 | cursor: default;
96 | }
97 | .calendar-menu {
98 | position: absolute;
99 | top: 0;
100 | left: 0;
101 | width: 180px;
102 | height: 150px;
103 | padding: 5px;
104 | font-size: 14px;
105 | display: none;
106 | overflow: hidden;
107 | }
108 | .calendar-menu-year-inner {
109 | text-align: center;
110 | padding-bottom: 5px;
111 | }
112 | .calendar-menu-year {
113 | width: 80px;
114 | line-height: 26px;
115 | text-align: center;
116 | border-width: 1px;
117 | border-style: solid;
118 | outline-style: none;
119 | resize: none;
120 | margin: 0;
121 | padding: 0;
122 | font-weight: bold;
123 | font-size: 14px;
124 | -moz-border-radius: 5px 5px 5px 5px;
125 | -webkit-border-radius: 5px 5px 5px 5px;
126 | border-radius: 5px 5px 5px 5px;
127 | }
128 | .calendar-menu-prev,
129 | .calendar-menu-next {
130 | display: inline-block;
131 | width: 25px;
132 | height: 28px;
133 | vertical-align: top;
134 | cursor: pointer;
135 | -moz-border-radius: 5px 5px 5px 5px;
136 | -webkit-border-radius: 5px 5px 5px 5px;
137 | border-radius: 5px 5px 5px 5px;
138 | }
139 | .calendar-menu-prev {
140 | margin-right: 10px;
141 | background: url('images/calendar_arrows.png') no-repeat 5px center;
142 | }
143 | .calendar-menu-next {
144 | margin-left: 10px;
145 | background: url('images/calendar_arrows.png') no-repeat -44px center;
146 | }
147 | .calendar-menu-month {
148 | text-align: center;
149 | cursor: pointer;
150 | font-weight: bold;
151 | -moz-border-radius: 5px 5px 5px 5px;
152 | -webkit-border-radius: 5px 5px 5px 5px;
153 | border-radius: 5px 5px 5px 5px;
154 | }
155 | .calendar-body th,
156 | .calendar-menu-month {
157 | color: #4d4d4d;
158 | }
159 | .calendar-day {
160 | color: #000000;
161 | }
162 | .calendar-sunday {
163 | color: #CC2222;
164 | }
165 | .calendar-saturday {
166 | color: #00ee00;
167 | }
168 | .calendar-today {
169 | color: #0000ff;
170 | }
171 | .calendar-menu-year {
172 | border-color: #95B8E7;
173 | }
174 | .calendar {
175 | border-color: #95B8E7;
176 | }
177 | .calendar-header {
178 | background: #E0ECFF;
179 | }
180 | .calendar-body,
181 | .calendar-menu {
182 | background: #ffffff;
183 | }
184 | .calendar-body th {
185 | background: #F4F4F4;
186 | padding: 4px 0;
187 | }
188 | .calendar-hover,
189 | .calendar-nav-hover,
190 | .calendar-menu-hover {
191 | background-color: #eaf2ff;
192 | color: #000000;
193 | }
194 | .calendar-hover {
195 | border: 1px solid #b7d2ff;
196 | padding: 0;
197 | }
198 | .calendar-selected {
199 | background-color: #ffe48d;
200 | color: #000000;
201 | border: 1px solid #ffab3f;
202 | padding: 0;
203 | }
204 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/window.css:
--------------------------------------------------------------------------------
1 | .window {
2 | overflow: hidden;
3 | padding: 5px;
4 | border-width: 1px;
5 | border-style: solid;
6 | }
7 | .window .window-header {
8 | background: transparent;
9 | padding: 0px 0px 6px 0px;
10 | }
11 | .window .window-body {
12 | border-width: 1px;
13 | border-style: solid;
14 | border-top-width: 0px;
15 | }
16 | .window .window-body-noheader {
17 | border-top-width: 1px;
18 | }
19 | .window .panel-body-nobottom {
20 | border-bottom-width: 0;
21 | }
22 | .window .window-header .panel-icon,
23 | .window .window-header .panel-tool {
24 | top: 50%;
25 | margin-top: -11px;
26 | }
27 | .window .window-header .panel-icon {
28 | left: 1px;
29 | }
30 | .window .window-header .panel-tool {
31 | right: 1px;
32 | }
33 | .window .window-header .panel-with-icon {
34 | padding-left: 18px;
35 | }
36 | .window-proxy {
37 | position: absolute;
38 | overflow: hidden;
39 | }
40 | .window-proxy-mask {
41 | position: absolute;
42 | filter: alpha(opacity=5);
43 | opacity: 0.05;
44 | }
45 | .window-mask {
46 | position: absolute;
47 | left: 0;
48 | top: 0;
49 | width: 100%;
50 | height: 100%;
51 | filter: alpha(opacity=40);
52 | opacity: 0.40;
53 | font-size: 1px;
54 | overflow: hidden;
55 | }
56 | .window,
57 | .window-shadow {
58 | position: absolute;
59 | -moz-border-radius: 5px 5px 5px 5px;
60 | -webkit-border-radius: 5px 5px 5px 5px;
61 | border-radius: 5px 5px 5px 5px;
62 | }
63 | .window-shadow {
64 | background: #ccc;
65 | -moz-box-shadow: 2px 2px 3px #cccccc;
66 | -webkit-box-shadow: 2px 2px 3px #cccccc;
67 | box-shadow: 2px 2px 3px #cccccc;
68 | filter: progid:DXImageTransform.Microsoft.Blur(pixelRadius=2,MakeShadow=false,ShadowOpacity=0.2);
69 | }
70 | .window,
71 | .window .window-body {
72 | border-color: #95B8E7;
73 | }
74 | .window {
75 | background-color: #E0ECFF;
76 | background: -webkit-linear-gradient(top,#EFF5FF 0,#E0ECFF 20%);
77 | background: -moz-linear-gradient(top,#EFF5FF 0,#E0ECFF 20%);
78 | background: -o-linear-gradient(top,#EFF5FF 0,#E0ECFF 20%);
79 | background: linear-gradient(to bottom,#EFF5FF 0,#E0ECFF 20%);
80 | background-repeat: repeat-x;
81 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#EFF5FF,endColorstr=#E0ECFF,GradientType=0);
82 | }
83 | .window-proxy {
84 | border: 1px dashed #95B8E7;
85 | }
86 | .window-proxy-mask,
87 | .window-mask {
88 | background: #ccc;
89 | }
90 | .window .panel-footer {
91 | border: 1px solid #95B8E7;
92 | position: relative;
93 | top: -1px;
94 | }
95 | .window-thinborder {
96 | padding: 0;
97 | }
98 | .window-thinborder .window-header {
99 | padding: 5px 5px 6px 5px;
100 | }
101 | .window-thinborder .window-body {
102 | border-width: 0px;
103 | }
104 | .window-thinborder .window-footer {
105 | border-left: transparent;
106 | border-right: transparent;
107 | border-bottom: transparent;
108 | }
109 | .window-thinborder .window-header .panel-icon,
110 | .window-thinborder .window-header .panel-tool {
111 | margin-top: -9px;
112 | margin-left: 5px;
113 | margin-right: 5px;
114 | }
115 | .window-noborder {
116 | border: 0;
117 | }
118 | .window.panel-hleft .window-header {
119 | padding: 0 6px 0 0;
120 | }
121 | .window.panel-hright .window-header {
122 | padding: 0 0 0 6px;
123 | }
124 | .window.panel-hleft>.panel-header .panel-title {
125 | top: auto;
126 | left: 16px;
127 | }
128 | .window.panel-hright>.panel-header .panel-title {
129 | top: auto;
130 | right: 16px;
131 | }
132 | .window.panel-hleft>.panel-header .panel-title-up,
133 | .window.panel-hright>.panel-header .panel-title-up {
134 | bottom: 0;
135 | }
136 | .window.panel-hleft .window-body {
137 | border-width: 1px 1px 1px 0;
138 | }
139 | .window.panel-hright .window-body {
140 | border-width: 1px 0 1px 1px;
141 | }
142 | .window.panel-hleft .window-header .panel-icon {
143 | top: 1px;
144 | margin-top: 0;
145 | left: 0;
146 | }
147 | .window.panel-hright .window-header .panel-icon {
148 | top: 1px;
149 | margin-top: 0;
150 | left: auto;
151 | right: 1px;
152 | }
153 | .window.panel-hleft .window-header .panel-tool,
154 | .window.panel-hright .window-header .panel-tool {
155 | margin-top: 0;
156 | top: auto;
157 | bottom: 1px;
158 | right: auto;
159 | margin-right: 0;
160 | left: 50%;
161 | margin-left: -11px;
162 | }
163 | .window.panel-hright .window-header .panel-tool {
164 | left: auto;
165 | right: 1px;
166 | }
167 | .window-thinborder.panel-hleft .window-header {
168 | padding: 5px 6px 5px 5px;
169 | }
170 | .window-thinborder.panel-hright .window-header {
171 | padding: 5px 5px 5px 6px;
172 | }
173 | .window-thinborder.panel-hleft>.panel-header .panel-title {
174 | left: 21px;
175 | }
176 | .window-thinborder.panel-hleft>.panel-header .panel-title-up,
177 | .window-thinborder.panel-hright>.panel-header .panel-title-up {
178 | bottom: 5px;
179 | }
180 | .window-thinborder.panel-hleft .window-header .panel-icon,
181 | .window-thinborder.panel-hright .window-header .panel-icon {
182 | margin-top: 5px;
183 | }
184 | .window-thinborder.panel-hleft .window-header .panel-tool,
185 | .window-thinborder.panel-hright .window-header .panel-tool {
186 | left: 16px;
187 | bottom: 5px;
188 | }
189 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/linkbutton.css:
--------------------------------------------------------------------------------
1 | .l-btn {
2 | text-decoration: none;
3 | display: inline-block;
4 | overflow: hidden;
5 | margin: 0;
6 | padding: 0;
7 | cursor: pointer;
8 | outline: none;
9 | text-align: center;
10 | vertical-align: middle;
11 | line-height: normal;
12 | }
13 | .l-btn-plain {
14 | border-width: 0;
15 | padding: 1px;
16 | }
17 | .l-btn-left {
18 | display: inline-block;
19 | position: relative;
20 | overflow: hidden;
21 | margin: 0;
22 | padding: 0;
23 | vertical-align: top;
24 | }
25 | .l-btn-text {
26 | display: inline-block;
27 | vertical-align: top;
28 | width: auto;
29 | line-height: 28px;
30 | font-size: 14px;
31 | padding: 0;
32 | margin: 0 6px;
33 | }
34 | .l-btn-icon {
35 | display: inline-block;
36 | width: 16px;
37 | height: 16px;
38 | line-height: 16px;
39 | position: absolute;
40 | top: 50%;
41 | margin-top: -8px;
42 | font-size: 1px;
43 | }
44 | .l-btn span span .l-btn-empty {
45 | display: inline-block;
46 | margin: 0;
47 | width: 16px;
48 | height: 24px;
49 | font-size: 1px;
50 | vertical-align: top;
51 | }
52 | .l-btn span .l-btn-icon-left {
53 | padding: 0 0 0 20px;
54 | background-position: left center;
55 | }
56 | .l-btn span .l-btn-icon-right {
57 | padding: 0 20px 0 0;
58 | background-position: right center;
59 | }
60 | .l-btn-icon-left .l-btn-text {
61 | margin: 0 6px 0 26px;
62 | }
63 | .l-btn-icon-left .l-btn-icon {
64 | left: 6px;
65 | }
66 | .l-btn-icon-right .l-btn-text {
67 | margin: 0 26px 0 6px;
68 | }
69 | .l-btn-icon-right .l-btn-icon {
70 | right: 6px;
71 | }
72 | .l-btn-icon-top .l-btn-text {
73 | margin: 20px 4px 0 4px;
74 | }
75 | .l-btn-icon-top .l-btn-icon {
76 | top: 4px;
77 | left: 50%;
78 | margin: 0 0 0 -8px;
79 | }
80 | .l-btn-icon-bottom .l-btn-text {
81 | margin: 0 4px 20px 4px;
82 | }
83 | .l-btn-icon-bottom .l-btn-icon {
84 | top: auto;
85 | bottom: 4px;
86 | left: 50%;
87 | margin: 0 0 0 -8px;
88 | }
89 | .l-btn-left .l-btn-empty {
90 | margin: 0 6px;
91 | width: 16px;
92 | }
93 | .l-btn-plain:hover {
94 | padding: 0;
95 | }
96 | .l-btn-focus {
97 | outline: #0000FF dotted thin;
98 | }
99 | .l-btn-large .l-btn-text {
100 | line-height: 44px;
101 | }
102 | .l-btn-large .l-btn-icon {
103 | width: 32px;
104 | height: 32px;
105 | line-height: 32px;
106 | margin-top: -16px;
107 | }
108 | .l-btn-large .l-btn-icon-left .l-btn-text {
109 | margin-left: 40px;
110 | }
111 | .l-btn-large .l-btn-icon-right .l-btn-text {
112 | margin-right: 40px;
113 | }
114 | .l-btn-large .l-btn-icon-top .l-btn-text {
115 | margin-top: 36px;
116 | line-height: 24px;
117 | min-width: 32px;
118 | }
119 | .l-btn-large .l-btn-icon-top .l-btn-icon {
120 | margin: 0 0 0 -16px;
121 | }
122 | .l-btn-large .l-btn-icon-bottom .l-btn-text {
123 | margin-bottom: 36px;
124 | line-height: 24px;
125 | min-width: 32px;
126 | }
127 | .l-btn-large .l-btn-icon-bottom .l-btn-icon {
128 | margin: 0 0 0 -16px;
129 | }
130 | .l-btn-large .l-btn-left .l-btn-empty {
131 | margin: 0 6px;
132 | width: 32px;
133 | }
134 | .l-btn {
135 | color: #444;
136 | background: #fafafa;
137 | background-repeat: repeat-x;
138 | border: 1px solid #bbb;
139 | background: -webkit-linear-gradient(top,#ffffff 0,#eeeeee 100%);
140 | background: -moz-linear-gradient(top,#ffffff 0,#eeeeee 100%);
141 | background: -o-linear-gradient(top,#ffffff 0,#eeeeee 100%);
142 | background: linear-gradient(to bottom,#ffffff 0,#eeeeee 100%);
143 | background-repeat: repeat-x;
144 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffff,endColorstr=#eeeeee,GradientType=0);
145 | -moz-border-radius: 5px 5px 5px 5px;
146 | -webkit-border-radius: 5px 5px 5px 5px;
147 | border-radius: 5px 5px 5px 5px;
148 | }
149 | .l-btn:hover {
150 | background: #eaf2ff;
151 | color: #000000;
152 | border: 1px solid #b7d2ff;
153 | filter: none;
154 | }
155 | .l-btn-plain {
156 | background: transparent;
157 | border-width: 0;
158 | filter: none;
159 | }
160 | .l-btn-outline {
161 | border-width: 1px;
162 | border-color: #b7d2ff;
163 | padding: 0;
164 | }
165 | .l-btn-plain:hover {
166 | background: #eaf2ff;
167 | color: #000000;
168 | border: 1px solid #b7d2ff;
169 | -moz-border-radius: 5px 5px 5px 5px;
170 | -webkit-border-radius: 5px 5px 5px 5px;
171 | border-radius: 5px 5px 5px 5px;
172 | }
173 | .l-btn-disabled,
174 | .l-btn-disabled:hover {
175 | opacity: 0.5;
176 | cursor: default;
177 | background: #fafafa;
178 | color: #444;
179 | background: -webkit-linear-gradient(top,#ffffff 0,#eeeeee 100%);
180 | background: -moz-linear-gradient(top,#ffffff 0,#eeeeee 100%);
181 | background: -o-linear-gradient(top,#ffffff 0,#eeeeee 100%);
182 | background: linear-gradient(to bottom,#ffffff 0,#eeeeee 100%);
183 | background-repeat: repeat-x;
184 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffffff,endColorstr=#eeeeee,GradientType=0);
185 | }
186 | .l-btn-disabled .l-btn-text,
187 | .l-btn-disabled .l-btn-icon {
188 | filter: alpha(opacity=50);
189 | }
190 | .l-btn-plain-disabled,
191 | .l-btn-plain-disabled:hover {
192 | background: transparent;
193 | filter: alpha(opacity=50);
194 | }
195 | .l-btn-selected,
196 | .l-btn-selected:hover {
197 | background: #ddd;
198 | filter: none;
199 | }
200 | .l-btn-plain-selected,
201 | .l-btn-plain-selected:hover {
202 | background: #ddd;
203 | }
204 |
--------------------------------------------------------------------------------
/lib/ConfigUtil.js:
--------------------------------------------------------------------------------
1 | class ConfigUtil {
2 | constructor(config) {
3 | this.config = config;
4 | }
5 |
6 | isConfigGateway(gatewaySid) {
7 | if(this.config['gateways'] && this.config['gateways'][gatewaySid]) {
8 | return true;
9 | }
10 |
11 | return false;
12 | }
13 |
14 | isHostGateway(gatewaySid) {
15 | if(this.config['gateways'] && this.config['gateways'][gatewaySid]) {
16 | if(this.config['gateways'][gatewaySid] instanceof Object) {
17 | if(this.config['gateways'][gatewaySid]['ip']) {
18 | return true;
19 | }
20 | }
21 | }
22 |
23 | return false;
24 | }
25 |
26 | getHosts() {
27 | var hosts = {};
28 |
29 | var gateways = this.getGateways();
30 | if(gateways) {
31 | for(var gatewaySid in gateways) {
32 | if(gateways[gatewaySid] instanceof Object) {
33 | if(gateways[gatewaySid]['ip']) {
34 | hosts[gatewaySid] = new Object();
35 | hosts[gatewaySid].ip = gateways[gatewaySid]['ip'];
36 | if(!gateways[gatewaySid]['port']) {
37 | hosts[gatewaySid].port = '9898';
38 | } else {
39 | hosts[gatewaySid].port = gateways[gatewaySid]['port'];
40 | }
41 | }
42 | }
43 | }
44 | }
45 |
46 | return hosts;
47 | }
48 |
49 | getGateways() {
50 | return this.config['gateways'];
51 | }
52 |
53 | getBindAddress() {
54 | return this.config['bindAddress'];
55 | }
56 |
57 | getSendWhoisCmdInterval() {
58 | return this.config['sendWhoisCmdInterval'] || 1 * 60 * 60 * 1000;
59 | }
60 |
61 | getAutoRemoveAccessoryInterval() {
62 | return this.config['autoRemoveAccessoryInterval'];
63 | }
64 |
65 | getMQTTConfig() {
66 | if(this.config['mqtt'] instanceof Object) {
67 | return this.config['mqtt'];
68 | }
69 | return null;
70 | }
71 |
72 | getManagePort() {
73 | if(this.config['manage'] instanceof Object) {
74 | return this.config['manage']['port'];
75 | }
76 | return null;
77 | }
78 |
79 | getManagePassword() {
80 | if(this.config['manage'] instanceof Object) {
81 | return this.config['manage']['password'];
82 | }
83 | return null;
84 | }
85 |
86 | getGatewayPasswordByGatewaySid(gatewaySid) {
87 | if(this.config['gateways'][gatewaySid] instanceof Object) {
88 | return this.config['gateways'][gatewaySid]['password'];
89 | } else {
90 | return this.config['gateways'][gatewaySid];
91 | }
92 | }
93 |
94 | getAccessoryConfig(deviceSid) {
95 | var result = {};
96 | if(this.config['defaultValue']) {
97 | result = this.config['defaultValue'][deviceSid];
98 | }
99 | return result;
100 | }
101 |
102 | getAccessoryAttribute(deviceSid, accessoryType, attributeName, defaultValue) {
103 | var defaultValueCfg = this.config['defaultValue'];
104 | if(null != defaultValueCfg) {
105 | if(null != defaultValueCfg[deviceSid]) {
106 | if(null != defaultValueCfg[deviceSid][accessoryType]) {
107 | if(null != defaultValueCfg[deviceSid][accessoryType][attributeName]) {
108 | return defaultValueCfg[deviceSid][accessoryType][attributeName];
109 | }
110 | }
111 | if(null != defaultValueCfg[deviceSid]['Global']){
112 | if(null != defaultValueCfg[deviceSid]['Global'][attributeName]) {
113 | return defaultValueCfg[deviceSid]['Global'][attributeName];
114 | }
115 | }
116 | }
117 | if(null != defaultValueCfg['Global']) {
118 | if(null != defaultValueCfg['Global'][attributeName]) {
119 | return defaultValueCfg['Global'][attributeName];
120 | }
121 | }
122 |
123 | }
124 |
125 | return defaultValue;
126 | }
127 |
128 | getAccessoryName(deviceSid, accessoryType) {
129 | var defaultValue = accessoryType + "_" + deviceSid.substring(deviceSid.length - 4);
130 | return this.getAccessoryAttribute(deviceSid, accessoryType, 'name', defaultValue);
131 | }
132 |
133 | getAccessoryDisable(deviceSid, accessoryType) {
134 | return this.getAccessoryAttribute(deviceSid, accessoryType, 'disable', false);
135 | }
136 |
137 | getAccessoryServiceType(deviceSid, accessoryType) {
138 | return this.getAccessoryAttribute(deviceSid, accessoryType, 'serviceType', null);
139 | }
140 |
141 | getAccessorySyncValue(deviceSid, accessoryType) {
142 | return this.getAccessoryAttribute(deviceSid, accessoryType, 'syncValue', false);
143 | }
144 |
145 | getAccessoryNoResponse(deviceSid, accessoryType) {
146 | return this.getAccessoryAttribute(deviceSid, accessoryType, 'disableNoResponse', false);
147 | }
148 |
149 | getAccessoryIgnoreWriteResult(deviceSid, accessoryType) {
150 | return this.getAccessoryAttribute(deviceSid, accessoryType, 'ignoreWriteResult', false);
151 | }
152 | }
153 |
154 | module.exports = ConfigUtil;
--------------------------------------------------------------------------------
/parser/PlugBaseParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class PlugBaseParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'PlugBase_Outlet': PlugBaseOutletParser
12 | }
13 | }
14 | }
15 | PlugBaseParser.modelName = ['plug'];
16 | module.exports = PlugBaseParser;
17 |
18 | class PlugBaseOutletParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | return this.Accessory.Categories.OUTLET;
25 | }
26 |
27 | getAccessoryInformation(deviceSid) {
28 | return {
29 | 'Manufacturer': 'Aqara',
30 | 'Model': 'Plug Base',
31 | 'SerialNumber': deviceSid
32 | };
33 | }
34 |
35 | getServices(jsonObj, accessoryName) {
36 | var that = this;
37 | var result = [];
38 |
39 | var service = new that.Service.Outlet(accessoryName);
40 | service.getCharacteristic(that.Characteristic.On);
41 | service.getCharacteristic(that.Characteristic.OutletInUse);
42 | result.push(service);
43 |
44 | return result;
45 | }
46 |
47 | parserAccessories(jsonObj) {
48 | var that = this;
49 | var deviceSid = jsonObj['sid'];
50 | var uuid = that.getAccessoryUUID(deviceSid);
51 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
52 | if(accessory) {
53 | var service = accessory.getService(that.Service.Outlet);
54 | var onCharacteristic = service.getCharacteristic(that.Characteristic.On);
55 | var outletInUseCharacteristic = service.getCharacteristic(that.Characteristic.OutletInUse);
56 | var value = that.getOnCharacteristicValue(jsonObj, null);
57 | if(null != value) {
58 | onCharacteristic.updateValue(value);
59 | outletInUseCharacteristic.updateValue(value);
60 | }
61 |
62 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
63 | if (onCharacteristic.listeners('get').length == 0) {
64 | onCharacteristic.on("get", function(callback) {
65 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
66 | that.platform.sendReadCommand(deviceSid, command).then(result => {
67 | var value = that.getOnCharacteristicValue(result, null);
68 | if(null != value) {
69 | outletInUseCharacteristic.updateValue(value);
70 | callback(null, value);
71 | } else {
72 | callback(new Error('get value fail: ' + result));
73 | }
74 | }).catch(function(err) {
75 | that.platform.log.error(err);
76 | callback(err);
77 | });
78 | });
79 | }
80 | }
81 |
82 | if (onCharacteristic.listeners('set').length == 0) {
83 | onCharacteristic.on("set", function(value, callback) {
84 | var model = that.platform.getDeviceModelBySid(deviceSid);
85 | var command = null;
86 | var proto_version_prefix = that.platform.getProtoVersionPrefixByProtoVersion(that.platform.getDeviceProtoVersionBySid(deviceSid));
87 | if(1 == proto_version_prefix) {
88 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","data":{"status":"' + (value ? 'on' : 'off') + '", "key": "${key}"}}';
89 | } else if(2 == proto_version_prefix) {
90 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","params":[{"channel_0":"' + (value ? 'on' : 'off') + '"}], "key": "${key}"}';
91 | } else {
92 | }
93 |
94 | if(that.platform.ConfigUtil.getAccessoryIgnoreWriteResult(deviceSid, that.accessoryType)) {
95 | that.platform.sendWriteCommandWithoutFeedback(deviceSid, command);
96 | that.callback2HB(deviceSid, this, callback, null);
97 | } else {
98 | that.platform.sendWriteCommand(deviceSid, command).then(result => {
99 | that.callback2HB(deviceSid, this, callback, null);
100 | }).catch(function(err) {
101 | that.platform.log.error(err);
102 | that.callback2HB(deviceSid, this, callback, err);
103 | });
104 | }
105 | });
106 | }
107 | }
108 | }
109 |
110 | getOnCharacteristicValue(jsonObj, defaultValue) {
111 | var value = null;
112 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(jsonObj['sid']));
113 | if(1 == proto_version_prefix) {
114 | value = this.getValueFrJsonObjData1(jsonObj, 'status');
115 | } else if(2 == proto_version_prefix) {
116 | value = this.getValueFrJsonObjData2(jsonObj, 'channel_0');
117 | } else {
118 | }
119 |
120 | if(value === 'on') {
121 | return true;
122 | } else if(value === 'off') {
123 | return false;
124 | } else {
125 | return defaultValue;
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/parser/PlugBase86Parser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class PlugBase86Parser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'PlugBase86_Outlet': PlugBase86OutletParser
12 | }
13 | }
14 | }
15 | PlugBase86Parser.modelName = ['86plug', 'ctrl_86plug', 'ctrl_86plug.aq1'];
16 | module.exports = PlugBase86Parser;
17 |
18 | class PlugBase86OutletParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | return this.Accessory.Categories.OUTLET;
25 | }
26 |
27 | getAccessoryInformation(deviceSid) {
28 | return {
29 | 'Manufacturer': 'Aqara',
30 | 'Model': 'Plug Base 86',
31 | 'SerialNumber': deviceSid
32 | };
33 | }
34 |
35 | getServices(jsonObj, accessoryName) {
36 | var that = this;
37 | var result = [];
38 |
39 | var service = new that.Service.Outlet(accessoryName);
40 | service.getCharacteristic(that.Characteristic.On);
41 | service.getCharacteristic(that.Characteristic.OutletInUse);
42 | result.push(service);
43 |
44 | return result;
45 | }
46 |
47 | parserAccessories(jsonObj) {
48 | var that = this;
49 | var deviceSid = jsonObj['sid'];
50 | var uuid = that.getAccessoryUUID(deviceSid);
51 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
52 | if(accessory) {
53 | var service = accessory.getService(that.Service.Outlet);
54 | var onCharacteristic = service.getCharacteristic(that.Characteristic.On);
55 | var outletInUseCharacteristic = service.getCharacteristic(that.Characteristic.OutletInUse);
56 | var value = that.getOnCharacteristicValue(jsonObj, null);
57 | if(null != value) {
58 | onCharacteristic.updateValue(value);
59 | outletInUseCharacteristic.updateValue(value);
60 | }
61 |
62 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
63 | if (onCharacteristic.listeners('get').length == 0) {
64 | onCharacteristic.on("get", function(callback) {
65 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
66 | that.platform.sendReadCommand(deviceSid, command).then(result => {
67 | var value = that.getOnCharacteristicValue(result, null);
68 | if(null != value) {
69 | outletInUseCharacteristic.updateValue(value);
70 | callback(null, value);
71 | } else {
72 | callback(new Error('get value fail: ' + result));
73 | }
74 | }).catch(function(err) {
75 | that.platform.log.error(err);
76 | callback(err);
77 | });
78 | });
79 | }
80 | }
81 |
82 | if (onCharacteristic.listeners('set').length == 0) {
83 | onCharacteristic.on("set", function(value, callback) {
84 | var model = that.platform.getDeviceModelBySid(deviceSid);
85 | var command = null;
86 | var proto_version_prefix = that.platform.getProtoVersionPrefixByProtoVersion(that.platform.getDeviceProtoVersionBySid(deviceSid));
87 | if(1 == proto_version_prefix) {
88 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","data":{"status":"' + (value ? 'on' : 'off') + '", "key": "${key}"}}';
89 | } else if(2 == proto_version_prefix) {
90 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","params":[{"channel_0":"' + (value ? 'on' : 'off') + '"}], "key": "${key}"}';
91 | } else {
92 | }
93 |
94 | if(that.platform.ConfigUtil.getAccessoryIgnoreWriteResult(deviceSid, that.accessoryType)) {
95 | that.platform.sendWriteCommandWithoutFeedback(deviceSid, command);
96 | that.callback2HB(deviceSid, this, callback, null);
97 | } else {
98 | that.platform.sendWriteCommand(deviceSid, command).then(result => {
99 | that.callback2HB(deviceSid, this, callback, null);
100 | }).catch(function(err) {
101 | that.platform.log.error(err);
102 | that.callback2HB(deviceSid, this, callback, err);
103 | });
104 | }
105 | });
106 | }
107 | }
108 | }
109 |
110 | getOnCharacteristicValue(jsonObj, defaultValue) {
111 | var value = null;
112 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(jsonObj['sid']));
113 | if(1 == proto_version_prefix) {
114 | value = this.getValueFrJsonObjData1(jsonObj, 'status');
115 | } else if(2 == proto_version_prefix) {
116 | value = this.getValueFrJsonObjData2(jsonObj, 'channel_0');
117 | } else {
118 | }
119 |
120 | if(value === 'on') {
121 | return true;
122 | } else if(value === 'off') {
123 | return false;
124 | } else {
125 | return defaultValue;
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/parser/ElectricCurtainParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class ElectricCurtainParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'ElectricCurtain_WindowCovering': ElectricCurtainWindowCoveringParser
12 | }
13 | }
14 | }
15 | ElectricCurtainParser.modelName = ['curtain'];
16 | module.exports = ElectricCurtainParser;
17 |
18 | class ElectricCurtainWindowCoveringParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | return this.Accessory.Categories.SENSOR;
25 | }
26 |
27 | getAccessoryInformation(deviceSid) {
28 | return {
29 | 'Manufacturer': 'Aqara',
30 | 'Model': 'Electric Curtain',
31 | 'SerialNumber': deviceSid
32 | };
33 | }
34 |
35 | getServices(jsonObj, accessoryName) {
36 | var that = this;
37 | var result = [];
38 |
39 | var service = new that.Service.WindowCovering(accessoryName);
40 | service.getCharacteristic(that.Characteristic.PositionState);
41 | service.getCharacteristic(that.Characteristic.CurrentPosition);
42 | service.getCharacteristic(that.Characteristic.TargetPosition);
43 | result.push(service);
44 |
45 | return result;
46 | }
47 |
48 | parserAccessories(jsonObj) {
49 | var that = this;
50 | var deviceSid = jsonObj['sid'];
51 | var uuid = that.getAccessoryUUID(deviceSid);
52 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
53 | if(accessory) {
54 | var service = accessory.getService(that.Service.WindowCovering);
55 | var positionStateCharacteristic = service.getCharacteristic(that.Characteristic.PositionState);
56 | var currentPositionCharacteristic = service.getCharacteristic(that.Characteristic.CurrentPosition);
57 | var targetPositionCharacteristic = service.getCharacteristic(that.Characteristic.TargetPosition);
58 | var value = that.getCurrentPositionCharacteristicValue(jsonObj, null);
59 | if(null != value) {
60 | positionStateCharacteristic.updateValue(that.Characteristic.PositionState.STOPPED);
61 | currentPositionCharacteristic.updateValue(value);
62 | targetPositionCharacteristic.updateValue(value);
63 | }
64 |
65 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
66 | if (currentPositionCharacteristic.listeners('get').length == 0) {
67 | currentPositionCharacteristic.on("get", function(callback) {
68 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
69 | that.platform.sendReadCommand(deviceSid, command).then(result => {
70 | var value = that.getCurrentPositionCharacteristicValue(result, null);
71 | if(null != value) {
72 | positionStateCharacteristic.updateValue(that.Characteristic.PositionState.STOPPED);
73 | targetPositionCharacteristic.updateValue(value);
74 | callback(null, value);
75 | } else {
76 | callback(new Error('get value fail: ' + result));
77 | }
78 | }).catch(function(err) {
79 | that.platform.log.error(err);
80 | callback(err);
81 | });
82 | });
83 | }
84 | }
85 |
86 | if (targetPositionCharacteristic.listeners('set').length == 0) {
87 | targetPositionCharacteristic.on("set", function(value, callback) {
88 | var model = that.platform.getDeviceModelBySid(deviceSid);
89 | var command = null;
90 | var proto_version_prefix = that.platform.getProtoVersionPrefixByProtoVersion(that.platform.getDeviceProtoVersionBySid(deviceSid));
91 | if(1 == proto_version_prefix) {
92 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","data":{"curtain_level":"' + value + '", "key": "${key}"}}';
93 | } else if(2 == proto_version_prefix) {
94 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","params":[{"curtain_level":' + value + '}], "key": "${key}"}';
95 | } else {
96 | }
97 |
98 | if(that.platform.ConfigUtil.getAccessoryIgnoreWriteResult(deviceSid, that.accessoryType)) {
99 | that.platform.sendWriteCommandWithoutFeedback(deviceSid, command);
100 | that.callback2HB(deviceSid, this, callback, null);
101 | } else {
102 | that.platform.sendWriteCommand(deviceSid, command).then(result => {
103 | that.callback2HB(deviceSid, this, callback, null);
104 | }).catch(function(err) {
105 | that.platform.log.error(err);
106 | that.callback2HB(deviceSid, this, callback, err);
107 | });
108 | }
109 | });
110 | }
111 | }
112 | }
113 |
114 | getCurrentPositionCharacteristicValue(jsonObj, defaultValue) {
115 | var value = this.getValueFrJsonObjData(jsonObj, 'curtain_level');
116 | if(value / 1.0 > 100) {
117 | return defaultValue;
118 | } else {
119 | return value / 1.0;
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/parser/SingleSwitchParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class SingleSwitchParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'SingleSwitch_Switch': SingleSwitchSwitchParser
12 | }
13 | }
14 | }
15 | SingleSwitchParser.modelName = ['ctrl_neutral1'];
16 | module.exports = SingleSwitchParser;
17 |
18 | class SingleSwitchSwitchParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | var serviceType = this.platform.ConfigUtil.getAccessoryServiceType(deviceSid, this.accessoryType);
25 | if(serviceType == 'Lightbulb') {
26 | return this.Accessory.Categories.LIGHTBULB;
27 | } else {
28 | return this.Accessory.Categories.SWITCH;
29 | }
30 | }
31 |
32 | getAccessoryInformation(deviceSid) {
33 | return {
34 | 'Manufacturer': 'Aqara',
35 | 'Model': 'Single Switch',
36 | 'SerialNumber': deviceSid
37 | };
38 | }
39 |
40 | getServices(jsonObj, accessoryName) {
41 | var that = this;
42 | var result = [];
43 |
44 | var service = null;
45 | var deviceSid = jsonObj['sid'];
46 | var serviceType = that.platform.ConfigUtil.getAccessoryServiceType(deviceSid, that.accessoryType);
47 | if(serviceType == 'Lightbulb') {
48 | service = new that.Service.Lightbulb(accessoryName);
49 | } else {
50 | service = new that.Service.Switch(accessoryName);
51 | }
52 | service.getCharacteristic(that.Characteristic.On);
53 | result.push(service);
54 |
55 | return result;
56 | }
57 |
58 | parserAccessories(jsonObj) {
59 | var that = this;
60 | var deviceSid = jsonObj['sid'];
61 | var uuid = that.getAccessoryUUID(deviceSid);
62 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
63 | if(accessory) {
64 | var service = null;
65 | var serviceType = that.platform.ConfigUtil.getAccessoryServiceType(deviceSid, that.accessoryType);
66 | if(serviceType == 'Lightbulb') {
67 | service = accessory.getService(that.Service.Lightbulb);
68 | } else {
69 | service = accessory.getService(that.Service.Switch);
70 | }
71 | var onCharacteristic = service.getCharacteristic(that.Characteristic.On);
72 | var value = that.getOnCharacteristicValue(jsonObj, null);
73 | if(null != value) {
74 | onCharacteristic.updateValue(value);
75 | }
76 |
77 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
78 | if (onCharacteristic.listeners('get').length == 0) {
79 | onCharacteristic.on("get", function(callback) {
80 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
81 | that.platform.sendReadCommand(deviceSid, command).then(result => {
82 | var value = that.getOnCharacteristicValue(result, null);
83 | if(null != value) {
84 | callback(null, value);
85 | } else {
86 | callback(new Error('get value fail: ' + result));
87 | }
88 | }).catch(function(err) {
89 | that.platform.log.error(err);
90 | callback(err);
91 | });
92 | });
93 | }
94 | }
95 |
96 | if(onCharacteristic.listeners('set').length == 0) {
97 | onCharacteristic.on("set", function(value, callback) {
98 | var model = that.platform.getDeviceModelBySid(deviceSid);
99 | var command = null;
100 | var proto_version_prefix = that.platform.getProtoVersionPrefixByProtoVersion(that.platform.getDeviceProtoVersionBySid(deviceSid));
101 | if(1 == proto_version_prefix) {
102 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","data":{"channel_0":"' + (value ? 'on' : 'off') + '", "key": "${key}"}"}';
103 | } else if(2 == proto_version_prefix) {
104 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","params":[{"channel_0":"' + (value ? 'on' : 'off') + '"}], "key": "${key}"}';
105 | } else {
106 | }
107 |
108 | if(that.platform.ConfigUtil.getAccessoryIgnoreWriteResult(deviceSid, that.accessoryType)) {
109 | that.platform.sendWriteCommandWithoutFeedback(deviceSid, command);
110 | that.callback2HB(deviceSid, this, callback, null);
111 | } else {
112 | that.platform.sendWriteCommand(deviceSid, command).then(result => {
113 | that.callback2HB(deviceSid, this, callback, null);
114 | }).catch(function(err) {
115 | that.platform.log.error(err);
116 | that.callback2HB(deviceSid, this, callback, err);
117 | });
118 | }
119 | });
120 | }
121 | }
122 | }
123 |
124 | getOnCharacteristicValue(jsonObj, defaultValue) {
125 | var value = this.getValueFrJsonObjData(jsonObj, 'channel_0');
126 | if(value === 'on') {
127 | return true;
128 | } else if(value === 'off') {
129 | return false;
130 | } else {
131 | return defaultValue;
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/parser/SingleSwitchLNParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class SingleSwitchLNParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'SingleSwitchLN_Switch': SingleSwitchLNSwitchParser
12 | }
13 | }
14 | }
15 | SingleSwitchLNParser.modelName = ['ctrl_ln1', 'ctrl_ln1.aq1'];
16 | module.exports = SingleSwitchLNParser;
17 |
18 | class SingleSwitchLNSwitchParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | var serviceType = this.platform.ConfigUtil.getAccessoryServiceType(deviceSid, this.accessoryType);
25 | if(serviceType == 'Lightbulb') {
26 | return this.Accessory.Categories.LIGHTBULB;
27 | } else {
28 | return this.Accessory.Categories.SWITCH;
29 | }
30 | }
31 |
32 | getAccessoryInformation(deviceSid) {
33 | return {
34 | 'Manufacturer': 'Aqara',
35 | 'Model': 'Single Switch LN',
36 | 'SerialNumber': deviceSid
37 | };
38 | }
39 |
40 | getServices(jsonObj, accessoryName) {
41 | var that = this;
42 | var result = [];
43 |
44 | var service = null;
45 | var deviceSid = jsonObj['sid'];
46 | var serviceType = that.platform.ConfigUtil.getAccessoryServiceType(deviceSid, that.accessoryType);
47 | if(serviceType == 'Lightbulb') {
48 | service = new that.Service.Lightbulb(accessoryName);
49 | } else {
50 | service = new that.Service.Switch(accessoryName);
51 | }
52 | service.getCharacteristic(that.Characteristic.On);
53 | result.push(service);
54 |
55 | return result;
56 | }
57 |
58 | parserAccessories(jsonObj) {
59 | var that = this;
60 | var deviceSid = jsonObj['sid'];
61 | var uuid = that.getAccessoryUUID(deviceSid);
62 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
63 | if(accessory) {
64 | var service = null;
65 | var serviceType = that.platform.ConfigUtil.getAccessoryServiceType(deviceSid, that.accessoryType);
66 | if(serviceType == 'Lightbulb') {
67 | service = accessory.getService(that.Service.Lightbulb);
68 | } else {
69 | service = accessory.getService(that.Service.Switch);
70 | }
71 | var onCharacteristic = service.getCharacteristic(that.Characteristic.On);
72 | var value = that.getOnCharacteristicValue(jsonObj, null);
73 | if(null != value) {
74 | onCharacteristic.updateValue(value);
75 | }
76 |
77 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
78 | if (onCharacteristic.listeners('get').length == 0) {
79 | onCharacteristic.on("get", function(callback) {
80 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
81 | that.platform.sendReadCommand(deviceSid, command).then(result => {
82 | var value = that.getOnCharacteristicValue(result, null);
83 | if(null != value) {
84 | callback(null, value);
85 | } else {
86 | callback(new Error('get value fail: ' + result));
87 | }
88 | }).catch(function(err) {
89 | that.platform.log.error(err);
90 | callback(err);
91 | });
92 | });
93 | }
94 | }
95 |
96 | if(onCharacteristic.listeners('set').length == 0) {
97 | onCharacteristic.on("set", function(value, callback) {
98 | var model = that.platform.getDeviceModelBySid(deviceSid);
99 | var command = null;
100 | var proto_version_prefix = that.platform.getProtoVersionPrefixByProtoVersion(that.platform.getDeviceProtoVersionBySid(deviceSid));
101 | if(1 == proto_version_prefix) {
102 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","data":{"channel_0":"' + (value ? 'on' : 'off') + '", "key": "${key}"}}';
103 | } else if(2 == proto_version_prefix) {
104 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","params":[{"channel_0":"' + (value ? 'on' : 'off') + '"}], "key": "${key}"}';
105 | } else {
106 | }
107 |
108 | if(that.platform.ConfigUtil.getAccessoryIgnoreWriteResult(deviceSid, that.accessoryType)) {
109 | that.platform.sendWriteCommandWithoutFeedback(deviceSid, command);
110 | that.callback2HB(deviceSid, this, callback, null);
111 | } else {
112 | that.platform.sendWriteCommand(deviceSid, command).then(result => {
113 | that.callback2HB(deviceSid, this, callback, null);
114 | }).catch(function(err) {
115 | that.platform.log.error(err);
116 | that.callback2HB(deviceSid, this, callback, err);
117 | });
118 | }
119 | });
120 | }
121 | }
122 | }
123 |
124 | getOnCharacteristicValue(jsonObj, defaultValue) {
125 | var value = this.getValueFrJsonObjData(jsonObj, 'channel_0');
126 | if(value === 'on') {
127 | return true;
128 | } else if(value === 'off') {
129 | return false;
130 | } else {
131 | return defaultValue;
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/parser/VibrationSensorParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class VibrationSensor extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'VibrationSensor_MotionSensor_Vibrate': VibrationSensorMotionSensorVibrateParser,
12 | 'VibrationSensor_MotionSensor_Tilt': VibrationSensorMotionSensorTiltParser,
13 | 'VibrationSensor_MotionSensor_FreeFall': VibrationSensorMotionSensorFreeFallParser
14 | }
15 | }
16 | }
17 | VibrationSensor.modelName = ['vibration'];
18 | module.exports = VibrationSensor;
19 |
20 | class VibrationSensorMotionSensorBaseParser extends AccessoryParser {
21 | constructor(platform, accessoryType) {
22 | super(platform, accessoryType)
23 | }
24 |
25 | getAccessoryCategory(deviceSid) {
26 | return this.Accessory.Categories.SENSOR;
27 | }
28 |
29 | getAccessoryInformation(deviceSid) {
30 | return {
31 | 'Manufacturer': 'Aqara',
32 | 'Model': 'Vibration Sensor',
33 | 'SerialNumber': deviceSid
34 | };
35 | }
36 |
37 | getServices(jsonObj, accessoryName) {
38 | var that = this;
39 | var result = [];
40 |
41 | var service = new that.Service.MotionSensor(accessoryName);
42 | service.getCharacteristic(that.Characteristic.MotionDetected);
43 | result.push(service);
44 |
45 | var batteryService = new that.Service.BatteryService(accessoryName);
46 | batteryService.getCharacteristic(that.Characteristic.StatusLowBattery);
47 | batteryService.getCharacteristic(that.Characteristic.BatteryLevel);
48 | batteryService.getCharacteristic(that.Characteristic.ChargingState);
49 | result.push(batteryService);
50 |
51 | return result;
52 | }
53 |
54 | parserAccessories(jsonObj) {
55 | var that = this;
56 | var deviceSid = jsonObj['sid'];
57 | var uuid = that.getAccessoryUUID(deviceSid);
58 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
59 | if(accessory) {
60 | var service = accessory.getService(that.Service.MotionSensor);
61 | var motionDetectedCharacteristic = service.getCharacteristic(that.Characteristic.MotionDetected);
62 | var value = that.getMotionDetectedCharacteristicValue(jsonObj, null);
63 | if(null != value) {
64 | motionDetectedCharacteristic.updateValue(value);
65 | if(true == value) {
66 | setTimeout(() => {
67 | motionDetectedCharacteristic.updateValue(false);
68 | }, 12 * 1000);
69 | }
70 | }
71 | /*
72 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
73 | if (motionDetectedCharacteristic.listeners('get').length == 0) {
74 | motionDetectedCharacteristic.on("get", function(callback) {
75 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
76 | that.platform.sendReadCommand(deviceSid, command).then(result => {
77 | var value = that.getMotionDetectedCharacteristicValue(result, null);
78 | if(null != value) {
79 | callback(null, value);
80 | } else {
81 | callback(new Error('get value fail: ' + result));
82 | }
83 | }).catch(function(err) {
84 | that.platform.log.error(err);
85 | callback(err);
86 | });
87 | });
88 | }
89 | }
90 | */
91 | that.parserBatteryService(accessory, jsonObj);
92 | }
93 | }
94 | }
95 |
96 | class VibrationSensorMotionSensorVibrateParser extends VibrationSensorMotionSensorBaseParser {
97 | getMotionDetectedCharacteristicValue(jsonObj, defaultValue) {
98 | var value = null;
99 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(jsonObj['sid']));
100 | if(1 == proto_version_prefix) {
101 | value = this.getValueFrJsonObjData1(jsonObj, 'status');
102 | } else if(2 == proto_version_prefix) {
103 | value = this.getValueFrJsonObjData2(jsonObj, 'motion_status');
104 | } else {
105 | }
106 |
107 | return (value === 'vibrate') ? true : null;
108 | }
109 | }
110 |
111 | class VibrationSensorMotionSensorTiltParser extends VibrationSensorMotionSensorBaseParser {
112 | getMotionDetectedCharacteristicValue(jsonObj, defaultValue) {
113 | var value = null;
114 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(jsonObj['sid']));
115 | if(1 == proto_version_prefix) {
116 | value = this.getValueFrJsonObjData1(jsonObj, 'status');
117 | } else if(2 == proto_version_prefix) {
118 | value = this.getValueFrJsonObjData2(jsonObj, 'motion_status');
119 | } else {
120 | }
121 |
122 | return (value === 'tilt') ? true : null;
123 | }
124 | }
125 |
126 | class VibrationSensorMotionSensorFreeFallParser extends VibrationSensorMotionSensorBaseParser {
127 | getMotionDetectedCharacteristicValue(jsonObj, defaultValue) {
128 | var value = null;
129 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(jsonObj['sid']));
130 | if(1 == proto_version_prefix) {
131 | value = this.getValueFrJsonObjData1(jsonObj, 'status');
132 | } else if(2 == proto_version_prefix) {
133 | value = this.getValueFrJsonObjData2(jsonObj, 'motion_status');
134 | } else {
135 | }
136 |
137 | return (value === 'free_fall') ? true : null;
138 | }
139 | }
--------------------------------------------------------------------------------
/parser/ElectricCurtainBatteryParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class ElectricCurtainBatteryParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'ElectricCurtainBattery_WindowCovering': ElectricCurtainBatteryWindowCoveringParser
12 | }
13 | }
14 | }
15 | ElectricCurtainBatteryParser.modelName = ['curtain.hagl04'];
16 | module.exports = ElectricCurtainBatteryParser;
17 |
18 | class ElectricCurtainBatteryWindowCoveringParser extends AccessoryParser {
19 | constructor(platform, accessoryType) {
20 | super(platform, accessoryType)
21 | }
22 |
23 | getAccessoryCategory(deviceSid) {
24 | return this.Accessory.Categories.SENSOR;
25 | }
26 |
27 | getAccessoryInformation(deviceSid) {
28 | return {
29 | 'Manufacturer': 'Aqara',
30 | 'Model': 'Electric Curtain B1',
31 | 'SerialNumber': deviceSid
32 | };
33 | }
34 |
35 | getServices(jsonObj, accessoryName) {
36 | var that = this;
37 | var result = [];
38 |
39 | var service = new that.Service.WindowCovering(accessoryName);
40 | service.getCharacteristic(that.Characteristic.PositionState);
41 | service.getCharacteristic(that.Characteristic.CurrentPosition);
42 | service.getCharacteristic(that.Characteristic.TargetPosition);
43 | result.push(service);
44 |
45 | var batteryService = new that.Service.BatteryService(accessoryName);
46 | batteryService.getCharacteristic(that.Characteristic.StatusLowBattery);
47 | batteryService.getCharacteristic(that.Characteristic.BatteryLevel);
48 | batteryService.getCharacteristic(that.Characteristic.ChargingState);
49 | result.push(batteryService);
50 |
51 | return result;
52 | }
53 |
54 | parserAccessories(jsonObj) {
55 | var that = this;
56 | var deviceSid = jsonObj['sid'];
57 | var uuid = that.getAccessoryUUID(deviceSid);
58 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
59 | if (accessory) {
60 | var service = accessory.getService(that.Service.WindowCovering);
61 | var positionStateCharacteristic = service.getCharacteristic(that.Characteristic.PositionState);
62 | var currentPositionCharacteristic = service.getCharacteristic(that.Characteristic.CurrentPosition);
63 | var targetPositionCharacteristic = service.getCharacteristic(that.Characteristic.TargetPosition);
64 | var value = that.getCurrentPositionCharacteristicValue(jsonObj, null);
65 | if (null != value) {
66 | positionStateCharacteristic.updateValue(that.Characteristic.PositionState.STOPPED);
67 | currentPositionCharacteristic.updateValue(value);
68 | targetPositionCharacteristic.updateValue(value);
69 | }
70 |
71 | if (that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
72 | if (currentPositionCharacteristic.listeners('get').length == 0) {
73 | currentPositionCharacteristic.on("get", function (callback) {
74 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
75 | that.platform.sendReadCommand(deviceSid, command).then(result => {
76 | var value = that.getCurrentPositionCharacteristicValue(result, null);
77 | if (null != value) {
78 | positionStateCharacteristic.updateValue(that.Characteristic.PositionState.STOPPED);
79 | targetPositionCharacteristic.updateValue(value);
80 | callback(null, value);
81 | } else {
82 | callback(new Error('get value fail: ' + result));
83 | }
84 | }).catch(function (err) {
85 | that.platform.log.error(err);
86 | callback(err);
87 | });
88 | });
89 | }
90 | }
91 |
92 | if (targetPositionCharacteristic.listeners('set').length == 0) {
93 | targetPositionCharacteristic.on("set", function (value, callback) {
94 | var model = that.platform.getDeviceModelBySid(deviceSid);
95 | var command = null;
96 | var proto_version_prefix = that.platform.getProtoVersionPrefixByProtoVersion(that.platform.getDeviceProtoVersionBySid(deviceSid));
97 | if (1 == proto_version_prefix) {
98 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","data":{"curtain_level":"' + value + '", "key": "${key}"}}';
99 | } else if (2 == proto_version_prefix) {
100 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","params":[{"curtain_level":' + value + '}], "key": "${key}"}';
101 | } else {}
102 |
103 | if (that.platform.ConfigUtil.getAccessoryIgnoreWriteResult(deviceSid, that.accessoryType)) {
104 | that.platform.sendWriteCommandWithoutFeedback(deviceSid, command);
105 | that.callback2HB(deviceSid, this, callback, null);
106 | } else {
107 | that.platform.sendWriteCommand(deviceSid, command).then(result => {
108 | that.callback2HB(deviceSid, this, callback, null);
109 | }).catch(function (err) {
110 | that.platform.log.error(err);
111 | that.callback2HB(deviceSid, this, callback, err);
112 | });
113 | }
114 | });
115 | }
116 |
117 | that.parserBatteryService(accessory, jsonObj);
118 | }
119 | }
120 |
121 | getCurrentPositionCharacteristicValue(jsonObj, defaultValue) {
122 | var value = this.getValueFrJsonObjData(jsonObj, 'curtain_level');
123 | if (value / 1.0 > 100) {
124 | return defaultValue;
125 | } else {
126 | return value / 1.0;
127 | }
128 | }
129 | }
--------------------------------------------------------------------------------
/parser/LockParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class LockParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | var parserInfo = {
11 | 'Lock_MotionSensor': LockMotionSensorParser
12 | };
13 |
14 | return parserInfo;
15 | }
16 | }
17 | LockParser.modelName = ['lock.aq1'];
18 | module.exports = LockParser;
19 |
20 | class LockMotionSensorParser extends AccessoryParser {
21 | constructor(platform, accessoryType) {
22 | super(platform, accessoryType)
23 | }
24 |
25 | getAccessoryCategory(deviceSid) {
26 | return this.Accessory.Categories.SENSOR;
27 | }
28 |
29 | getAccessoryInformation(deviceSid) {
30 | return {
31 | 'Manufacturer': 'Aqara',
32 | 'Model': 'Lock',
33 | 'SerialNumber': deviceSid
34 | };
35 | }
36 |
37 | getServices(jsonObj, accessoryName) {
38 | var that = this;
39 | var result = [];
40 |
41 | var deviceSid = jsonObj['sid'];
42 |
43 | var mainMotionSensorService = new that.Service.MotionSensor(accessoryName);
44 | mainMotionSensorService.subtype = 'main';
45 | mainMotionSensorService.getCharacteristic(that.Characteristic.MotionDetected);
46 | result.push(mainMotionSensorService);
47 |
48 | var batteryService = new that.Service.BatteryService(accessoryName);
49 | batteryService.getCharacteristic(that.Characteristic.StatusLowBattery);
50 | batteryService.getCharacteristic(that.Characteristic.BatteryLevel);
51 | batteryService.getCharacteristic(that.Characteristic.ChargingState);
52 | result.push(batteryService);
53 |
54 | // get Config
55 | var accessoryConfig = that.platform.ConfigUtil.getAccessoryConfig(deviceSid);
56 | if (accessoryConfig) {
57 | for (var key in accessoryConfig) {
58 | if(key.indexOf('Lock_MotionSensor_') > -1) {
59 | var id = key.substring('Lock_MotionSensor_'.length, key.length);
60 | var subMotionSensorName = that.platform.ConfigUtil.getAccessoryName(deviceSid, 'Lock_MotionSensor_' + id);
61 | var subMotionSensorService = new that.Service.MotionSensor(subMotionSensorName);
62 | subMotionSensorService.subtype = id;
63 | result.push(subMotionSensorService);
64 | }
65 | }
66 | }
67 |
68 | return result;
69 | }
70 |
71 | parserAccessories(jsonObj) {
72 | var that = this;
73 | var deviceSid = jsonObj['sid'];
74 | var uuid = that.getAccessoryUUID(deviceSid);
75 | var accessoryName = that.platform.ConfigUtil.getAccessoryName(deviceSid, that.accessoryType);
76 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
77 | if(accessory) {
78 | var mainMotionSensorService = accessory.getServiceByUUIDAndSubType(accessoryName, 'main');
79 | var mainMotionSensorService = mainMotionSensorService.getCharacteristic(that.Characteristic.MotionDetected);
80 | var value = that.getMotionDetectedCharacteristicValue(jsonObj, null);
81 | if(null != value) {
82 | mainMotionSensorService.updateValue(true);
83 | setTimeout(() => {
84 | mainMotionSensorService.updateValue(false);
85 | }, 1 * 60 * 1000);
86 |
87 | var subMotionSensorName = that.platform.ConfigUtil.getAccessoryName(deviceSid, 'Lock_MotionSensor_' + value);
88 | var subMotionSensorService = accessory.getServiceByUUIDAndSubType(subMotionSensorName, value);
89 | if(subMotionSensorService) {
90 | var subMotionDetectedCharacteristic = subMotionSensorService.getCharacteristic(that.Characteristic.MotionDetected);
91 | subMotionDetectedCharacteristic.updateValue(true);
92 | setTimeout(() => {
93 | subMotionDetectedCharacteristic.updateValue(false);
94 | }, 1 * 60 * 1000);
95 | }
96 | }
97 | /*
98 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
99 | if (motionDetectedCharacteristic.listeners('get').length == 0) {
100 | motionDetectedCharacteristic.on("get", function(callback) {
101 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
102 | that.platform.sendReadCommand(deviceSid, command).then(result => {
103 | var value = that.getMotionDetectedCharacteristicValue(result, null);
104 | if(null != value) {
105 | callback(null, value);
106 | } else {
107 | callback(new Error('get value fail: ' + result));
108 | }
109 | }).catch(function(err) {
110 | that.platform.log.error(err);
111 | callback(err);
112 | });
113 | });
114 | }
115 | }
116 | */
117 | that.parserBatteryService(accessory, jsonObj);
118 | }
119 | }
120 |
121 | getMotionDetectedCharacteristicValue(jsonObj, defaultValue) {
122 | var success_value = null;
123 | var wrong_value = null;
124 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(jsonObj['sid']));
125 | if(1 == proto_version_prefix) {
126 | success_value = this.getValueFrJsonObjData1(jsonObj, 'fing_verified') || this.getValueFrJsonObjData1(jsonObj, 'card_verified') || this.getValueFrJsonObjData1(jsonObj, 'psw_verified');
127 | wrong_value = this.getValueFrJsonObjData1(jsonObj, 'verified_wrong');
128 | } else if(2 == proto_version_prefix) {
129 | success_value = this.getValueFrJsonObjData2(jsonObj, 'fing_verified') || this.getValueFrJsonObjData2(jsonObj, 'card_verified') || this.getValueFrJsonObjData2(jsonObj, 'psw_verified');
130 | wrong_value = this.getValueFrJsonObjData2(jsonObj, 'verified_wrong');
131 | } else {
132 | }
133 |
134 | return wrong_value ? defaultValue : success_value;
135 | }
136 | }
--------------------------------------------------------------------------------
/manage/easyui/themes/default/panel.css:
--------------------------------------------------------------------------------
1 | .panel {
2 | overflow: hidden;
3 | text-align: left;
4 | margin: 0;
5 | border: 0;
6 | -moz-border-radius: 0 0 0 0;
7 | -webkit-border-radius: 0 0 0 0;
8 | border-radius: 0 0 0 0;
9 | }
10 | .panel-header,
11 | .panel-body {
12 | border-width: 1px;
13 | border-style: solid;
14 | }
15 | .panel-header {
16 | padding: 5px;
17 | position: relative;
18 | }
19 | .panel-title {
20 | background: url('images/blank.gif') no-repeat;
21 | }
22 | .panel-header-noborder {
23 | border-width: 0 0 1px 0;
24 | }
25 | .panel-body {
26 | overflow: auto;
27 | border-top-width: 0;
28 | padding: 0;
29 | }
30 | .panel-body-noheader {
31 | border-top-width: 1px;
32 | }
33 | .panel-body-noborder {
34 | border-width: 0px;
35 | }
36 | .panel-body-nobottom {
37 | border-bottom-width: 0;
38 | }
39 | .panel-with-icon {
40 | padding-left: 18px;
41 | }
42 | .panel-icon,
43 | .panel-tool {
44 | position: absolute;
45 | top: 50%;
46 | margin-top: -8px;
47 | height: 16px;
48 | overflow: hidden;
49 | }
50 | .panel-icon {
51 | left: 5px;
52 | width: 16px;
53 | }
54 | .panel-tool {
55 | right: 5px;
56 | width: auto;
57 | }
58 | .panel-tool a {
59 | display: inline-block;
60 | width: 16px;
61 | height: 16px;
62 | opacity: 0.6;
63 | filter: alpha(opacity=60);
64 | margin: 0 0 0 2px;
65 | vertical-align: top;
66 | }
67 | .panel-tool a:hover {
68 | opacity: 1;
69 | filter: alpha(opacity=100);
70 | background-color: #eaf2ff;
71 | -moz-border-radius: 3px 3px 3px 3px;
72 | -webkit-border-radius: 3px 3px 3px 3px;
73 | border-radius: 3px 3px 3px 3px;
74 | }
75 | .panel-loading {
76 | padding: 11px 0px 10px 30px;
77 | }
78 | .panel-noscroll {
79 | overflow: hidden;
80 | }
81 | .panel-fit,
82 | .panel-fit body {
83 | height: 100%;
84 | margin: 0;
85 | padding: 0;
86 | border: 0;
87 | overflow: hidden;
88 | }
89 | .panel-loading {
90 | background: url('images/loading.gif') no-repeat 10px 10px;
91 | }
92 | .panel-tool-close {
93 | background: url('images/panel_tools.png') no-repeat -16px 0px;
94 | }
95 | .panel-tool-min {
96 | background: url('images/panel_tools.png') no-repeat 0px 0px;
97 | }
98 | .panel-tool-max {
99 | background: url('images/panel_tools.png') no-repeat 0px -16px;
100 | }
101 | .panel-tool-restore {
102 | background: url('images/panel_tools.png') no-repeat -16px -16px;
103 | }
104 | .panel-tool-collapse {
105 | background: url('images/panel_tools.png') no-repeat -32px 0;
106 | }
107 | .panel-tool-expand {
108 | background: url('images/panel_tools.png') no-repeat -32px -16px;
109 | }
110 | .panel-header,
111 | .panel-body {
112 | border-color: #95B8E7;
113 | }
114 | .panel-header {
115 | background-color: #E0ECFF;
116 | background: -webkit-linear-gradient(top,#EFF5FF 0,#E0ECFF 100%);
117 | background: -moz-linear-gradient(top,#EFF5FF 0,#E0ECFF 100%);
118 | background: -o-linear-gradient(top,#EFF5FF 0,#E0ECFF 100%);
119 | background: linear-gradient(to bottom,#EFF5FF 0,#E0ECFF 100%);
120 | background-repeat: repeat-x;
121 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#EFF5FF,endColorstr=#E0ECFF,GradientType=0);
122 | }
123 | .panel-body {
124 | background-color: #ffffff;
125 | color: #000000;
126 | font-size: 14px;
127 | }
128 | .panel-title {
129 | font-size: 14px;
130 | font-weight: bold;
131 | color: #0E2D5F;
132 | height: 20px;
133 | line-height: 20px;
134 | }
135 | .panel-footer {
136 | border: 1px solid #95B8E7;
137 | overflow: hidden;
138 | background: #F4F4F4;
139 | }
140 | .panel-footer-noborder {
141 | border-width: 1px 0 0 0;
142 | }
143 | .panel-hleft,
144 | .panel-hright {
145 | position: relative;
146 | }
147 | .panel-hleft>.panel-body,
148 | .panel-hright>.panel-body {
149 | position: absolute;
150 | }
151 | .panel-hleft>.panel-header {
152 | float: left;
153 | }
154 | .panel-hright>.panel-header {
155 | float: right;
156 | }
157 | .panel-hleft>.panel-body {
158 | border-top-width: 1px;
159 | border-left-width: 0;
160 | }
161 | .panel-hright>.panel-body {
162 | border-top-width: 1px;
163 | border-right-width: 0;
164 | }
165 | .panel-hleft>.panel-body-nobottom {
166 | border-bottom-width: 1px;
167 | border-right-width: 0;
168 | }
169 | .panel-hright>.panel-body-nobottom {
170 | border-bottom-width: 1px;
171 | border-left-width: 0;
172 | }
173 | .panel-hleft>.panel-footer {
174 | position: absolute;
175 | right: 0;
176 | }
177 | .panel-hright>.panel-footer {
178 | position: absolute;
179 | left: 0;
180 | }
181 | .panel-hleft>.panel-header-noborder {
182 | border-width: 0 1px 0 0;
183 | }
184 | .panel-hright>.panel-header-noborder {
185 | border-width: 0 0 0 1px;
186 | }
187 | .panel-hleft>.panel-body-noborder {
188 | border-width: 0;
189 | }
190 | .panel-hright>.panel-body-noborder {
191 | border-width: 0;
192 | }
193 | .panel-hleft>.panel-body-noheader {
194 | border-left-width: 1px;
195 | }
196 | .panel-hright>.panel-body-noheader {
197 | border-right-width: 1px;
198 | }
199 | .panel-hleft>.panel-footer-noborder {
200 | border-width: 0 0 0 1px;
201 | }
202 | .panel-hright>.panel-footer-noborder {
203 | border-width: 0 1px 0 0;
204 | }
205 | .panel-hleft>.panel-header .panel-icon,
206 | .panel-hright>.panel-header .panel-icon {
207 | margin-top: 0;
208 | top: 5px;
209 | left: 50%;
210 | margin-left: -8px;
211 | }
212 | .panel-hleft>.panel-header .panel-title,
213 | .panel-hright>.panel-header .panel-title {
214 | position: absolute;
215 | min-width: 16px;
216 | left: 25px;
217 | top: 5px;
218 | bottom: auto;
219 | white-space: nowrap;
220 | word-wrap: normal;
221 | -webkit-transform: rotate(90deg);
222 | -webkit-transform-origin: 0 0;
223 | -moz-transform: rotate(90deg);
224 | -moz-transform-origin: 0 0;
225 | -o-transform: rotate(90deg);
226 | -o-transform-origin: 0 0;
227 | transform: rotate(90deg);
228 | transform-origin: 0 0;
229 | }
230 | .panel-hleft>.panel-header .panel-title-up,
231 | .panel-hright>.panel-header .panel-title-up {
232 | position: absolute;
233 | min-width: 16px;
234 | left: 21px;
235 | top: auto;
236 | bottom: 0px;
237 | text-align: right;
238 | white-space: nowrap;
239 | word-wrap: normal;
240 | -webkit-transform: rotate(-90deg);
241 | -webkit-transform-origin: 0 0;
242 | -moz-transform: rotate(-90deg);
243 | -moz-transform-origin: 0 0;
244 | -o-transform: rotate(-90deg);
245 | -o-transform-origin: 0 0;
246 | transform: rotate(-90deg);
247 | transform-origin: 0 16px;
248 | }
249 | .panel-hleft>.panel-header .panel-with-icon.panel-title-up,
250 | .panel-hright>.panel-header .panel-with-icon.panel-title-up {
251 | padding-left: 0;
252 | padding-right: 18px;
253 | }
254 | .panel-hleft>.panel-header .panel-tool,
255 | .panel-hright>.panel-header .panel-tool {
256 | top: auto;
257 | bottom: 5px;
258 | width: 16px;
259 | height: auto;
260 | left: 50%;
261 | margin-left: -8px;
262 | margin-top: 0;
263 | }
264 | .panel-hleft>.panel-header .panel-tool a,
265 | .panel-hright>.panel-header .panel-tool a {
266 | margin: 2px 0 0 0;
267 | }
268 |
--------------------------------------------------------------------------------
/manage/easyui/themes/default/datagrid.css:
--------------------------------------------------------------------------------
1 | .datagrid .panel-body {
2 | overflow: hidden;
3 | position: relative;
4 | }
5 | .datagrid-view {
6 | position: relative;
7 | overflow: hidden;
8 | }
9 | .datagrid-view1,
10 | .datagrid-view2 {
11 | position: absolute;
12 | overflow: hidden;
13 | top: 0;
14 | }
15 | .datagrid-view1 {
16 | left: 0;
17 | }
18 | .datagrid-view2 {
19 | right: 0;
20 | }
21 | .datagrid-mask {
22 | position: absolute;
23 | left: 0;
24 | top: 0;
25 | width: 100%;
26 | height: 100%;
27 | opacity: 0.3;
28 | filter: alpha(opacity=30);
29 | display: none;
30 | }
31 | .datagrid-mask-msg {
32 | position: absolute;
33 | top: 50%;
34 | margin-top: -20px;
35 | padding: 10px 5px 10px 30px;
36 | width: auto;
37 | height: 16px;
38 | border-width: 2px;
39 | border-style: solid;
40 | display: none;
41 | }
42 | .datagrid-empty {
43 | position: absolute;
44 | left: 0;
45 | top: 0;
46 | width: 100%;
47 | height: 25px;
48 | line-height: 25px;
49 | text-align: center;
50 | }
51 | .datagrid-sort-icon {
52 | padding: 0;
53 | display: none;
54 | }
55 | .datagrid-toolbar {
56 | height: auto;
57 | padding: 1px 2px;
58 | border-width: 0 0 1px 0;
59 | border-style: solid;
60 | }
61 | .datagrid-btn-separator {
62 | float: left;
63 | height: 24px;
64 | border-left: 1px solid #ccc;
65 | border-right: 1px solid #fff;
66 | margin: 2px 1px;
67 | }
68 | .datagrid .datagrid-pager {
69 | display: block;
70 | margin: 0;
71 | border-width: 1px 0 0 0;
72 | border-style: solid;
73 | }
74 | .datagrid .datagrid-pager-top {
75 | border-width: 0 0 1px 0;
76 | }
77 | .datagrid-header {
78 | overflow: hidden;
79 | cursor: default;
80 | border-width: 0 0 1px 0;
81 | border-style: solid;
82 | }
83 | .datagrid-header-inner {
84 | float: left;
85 | width: 10000px;
86 | }
87 | .datagrid-header-row,
88 | .datagrid-row {
89 | height: 32px;
90 | }
91 | .datagrid-header td,
92 | .datagrid-body td,
93 | .datagrid-footer td {
94 | border-width: 0 1px 1px 0;
95 | border-style: dotted;
96 | margin: 0;
97 | padding: 0;
98 | }
99 | .datagrid-cell,
100 | .datagrid-cell-group,
101 | .datagrid-header-rownumber,
102 | .datagrid-cell-rownumber {
103 | margin: 0;
104 | padding: 0 4px;
105 | white-space: nowrap;
106 | word-wrap: normal;
107 | overflow: hidden;
108 | height: 18px;
109 | line-height: 18px;
110 | font-size: 14px;
111 | }
112 | .datagrid-header .datagrid-cell {
113 | height: auto;
114 | }
115 | .datagrid-header .datagrid-cell span {
116 | font-size: 14px;
117 | }
118 | .datagrid-cell-group {
119 | text-align: center;
120 | text-overflow: ellipsis;
121 | }
122 | .datagrid-header-rownumber,
123 | .datagrid-cell-rownumber {
124 | width: 30px;
125 | text-align: center;
126 | margin: 0;
127 | padding: 0;
128 | }
129 | .datagrid-body {
130 | margin: 0;
131 | padding: 0;
132 | overflow: auto;
133 | zoom: 1;
134 | }
135 | .datagrid-view1 .datagrid-body-inner {
136 | padding-bottom: 20px;
137 | }
138 | .datagrid-view1 .datagrid-body {
139 | overflow: hidden;
140 | }
141 | .datagrid-footer {
142 | overflow: hidden;
143 | }
144 | .datagrid-footer-inner {
145 | border-width: 1px 0 0 0;
146 | border-style: solid;
147 | width: 10000px;
148 | float: left;
149 | }
150 | .datagrid-row-editing .datagrid-cell {
151 | height: auto;
152 | }
153 | .datagrid-header-check,
154 | .datagrid-cell-check {
155 | padding: 0;
156 | width: 27px;
157 | height: 18px;
158 | font-size: 1px;
159 | text-align: center;
160 | overflow: hidden;
161 | }
162 | .datagrid-header-check input,
163 | .datagrid-cell-check input {
164 | margin: 0;
165 | padding: 0;
166 | width: 15px;
167 | height: 18px;
168 | }
169 | .datagrid-resize-proxy {
170 | position: absolute;
171 | width: 1px;
172 | height: 10000px;
173 | top: 0;
174 | cursor: e-resize;
175 | display: none;
176 | }
177 | .datagrid-body .datagrid-editable {
178 | margin: 0;
179 | padding: 0;
180 | }
181 | .datagrid-body .datagrid-editable table {
182 | width: 100%;
183 | height: 100%;
184 | }
185 | .datagrid-body .datagrid-editable td {
186 | border: 0;
187 | margin: 0;
188 | padding: 0;
189 | }
190 | .datagrid-view .datagrid-editable-input {
191 | margin: 0;
192 | padding: 2px 4px;
193 | border: 1px solid #95B8E7;
194 | font-size: 14px;
195 | outline-style: none;
196 | -moz-border-radius: 0 0 0 0;
197 | -webkit-border-radius: 0 0 0 0;
198 | border-radius: 0 0 0 0;
199 | }
200 | .datagrid-view .validatebox-invalid {
201 | border-color: #ffa8a8;
202 | }
203 | .datagrid-sort .datagrid-sort-icon {
204 | display: inline;
205 | padding: 0 13px 0 0;
206 | background: url('images/datagrid_icons.png') no-repeat -64px center;
207 | }
208 | .datagrid-sort-desc .datagrid-sort-icon {
209 | display: inline;
210 | padding: 0 13px 0 0;
211 | background: url('images/datagrid_icons.png') no-repeat -16px center;
212 | }
213 | .datagrid-sort-asc .datagrid-sort-icon {
214 | display: inline;
215 | padding: 0 13px 0 0;
216 | background: url('images/datagrid_icons.png') no-repeat 0px center;
217 | }
218 | .datagrid-row-collapse {
219 | background: url('images/datagrid_icons.png') no-repeat -48px center;
220 | }
221 | .datagrid-row-expand {
222 | background: url('images/datagrid_icons.png') no-repeat -32px center;
223 | }
224 | .datagrid-mask-msg {
225 | background: #ffffff url('images/loading.gif') no-repeat scroll 5px center;
226 | }
227 | .datagrid-header,
228 | .datagrid-td-rownumber {
229 | background-color: #efefef;
230 | background: -webkit-linear-gradient(top,#F9F9F9 0,#efefef 100%);
231 | background: -moz-linear-gradient(top,#F9F9F9 0,#efefef 100%);
232 | background: -o-linear-gradient(top,#F9F9F9 0,#efefef 100%);
233 | background: linear-gradient(to bottom,#F9F9F9 0,#efefef 100%);
234 | background-repeat: repeat-x;
235 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#F9F9F9,endColorstr=#efefef,GradientType=0);
236 | }
237 | .datagrid-cell-rownumber {
238 | color: #000000;
239 | }
240 | .datagrid-resize-proxy {
241 | background: #aac5e7;
242 | }
243 | .datagrid-mask {
244 | background: #ccc;
245 | }
246 | .datagrid-mask-msg {
247 | border-color: #95B8E7;
248 | }
249 | .datagrid-toolbar,
250 | .datagrid-pager {
251 | background: #F4F4F4;
252 | }
253 | .datagrid-header,
254 | .datagrid-toolbar,
255 | .datagrid-pager,
256 | .datagrid-footer-inner {
257 | border-color: #dddddd;
258 | }
259 | .datagrid-header td,
260 | .datagrid-body td,
261 | .datagrid-footer td {
262 | border-color: #ccc;
263 | }
264 | .datagrid-htable,
265 | .datagrid-btable,
266 | .datagrid-ftable {
267 | color: #000000;
268 | border-collapse: separate;
269 | }
270 | .datagrid-row-alt {
271 | background: #fafafa;
272 | }
273 | .datagrid-row-over,
274 | .datagrid-header td.datagrid-header-over {
275 | background: #eaf2ff;
276 | color: #000000;
277 | cursor: default;
278 | }
279 | .datagrid-row-selected {
280 | background: #ffe48d;
281 | color: #000000;
282 | }
283 | .datagrid-row-editing .textbox,
284 | .datagrid-row-editing .textbox-text {
285 | -moz-border-radius: 0 0 0 0;
286 | -webkit-border-radius: 0 0 0 0;
287 | border-radius: 0 0 0 0;
288 | }
289 | .datagrid-header .datagrid-filter-row td.datagrid-header-over {
290 | background: inherit;
291 | }
292 |
--------------------------------------------------------------------------------
/parser/DuplexSwitchParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class DuplexSwitchParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'DuplexSwitch_Switch_Left': DuplexSwitchSwitchLeftParser,
12 | 'DuplexSwitch_Switch_Right': DuplexSwitchSwitchRightParser
13 | }
14 | }
15 | }
16 | DuplexSwitchParser.modelName = ['ctrl_neutral2'];
17 | module.exports = DuplexSwitchParser;
18 |
19 | class DuplexSwitchSwitchBaseParser extends AccessoryParser {
20 | constructor(platform, accessoryType) {
21 | super(platform, accessoryType)
22 | }
23 |
24 | getAccessoryCategory(deviceSid) {
25 | var serviceType = this.platform.ConfigUtil.getAccessoryServiceType(deviceSid, this.accessoryType);
26 | if(serviceType == 'Lightbulb') {
27 | return this.Accessory.Categories.LIGHTBULB;
28 | } else {
29 | return this.Accessory.Categories.SWITCH;
30 | }
31 | }
32 |
33 | getAccessoryInformation(deviceSid) {
34 | return {
35 | 'Manufacturer': 'Aqara',
36 | 'Model': 'Duplex Switch',
37 | 'SerialNumber': deviceSid
38 | };
39 | }
40 |
41 | getServices(jsonObj, accessoryName) {
42 | var that = this;
43 | var result = [];
44 |
45 | var service = null;
46 | var deviceSid = jsonObj['sid'];
47 | var serviceType = that.platform.ConfigUtil.getAccessoryServiceType(deviceSid, that.accessoryType);
48 | if(serviceType == 'Lightbulb') {
49 | service = new that.Service.Lightbulb(accessoryName);
50 | } else {
51 | service = new that.Service.Switch(accessoryName);
52 | }
53 | service.getCharacteristic(that.Characteristic.On);
54 | result.push(service);
55 |
56 | return result;
57 | }
58 |
59 | parserAccessories(jsonObj) {
60 | var that = this;
61 | var deviceSid = jsonObj['sid'];
62 | var uuid = that.getAccessoryUUID(deviceSid);
63 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
64 | if(accessory) {
65 | var service = null;
66 | var serviceType = that.platform.ConfigUtil.getAccessoryServiceType(deviceSid, that.accessoryType);
67 | if(serviceType == 'Lightbulb') {
68 | service = accessory.getService(that.Service.Lightbulb);
69 | } else {
70 | service = accessory.getService(that.Service.Switch);
71 | }
72 | var onCharacteristic = service.getCharacteristic(that.Characteristic.On);
73 | var value = that.getOnCharacteristicValue(jsonObj, null);
74 | if(null != value) {
75 | onCharacteristic.updateValue(value);
76 | }
77 |
78 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
79 | if (onCharacteristic.listeners('get').length == 0) {
80 | onCharacteristic.on("get", function(callback) {
81 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
82 | that.platform.sendReadCommand(deviceSid, command).then(result => {
83 | var value = that.getOnCharacteristicValue(result, null);
84 | if(null != value) {
85 | callback(null, value);
86 | } else {
87 | callback(new Error('get value fail: ' + result));
88 | }
89 | }).catch(function(err) {
90 | that.platform.log.error(err);
91 | callback(err);
92 | });
93 | });
94 | }
95 | }
96 |
97 | if(onCharacteristic.listeners('set').length == 0) {
98 | onCharacteristic.on("set", function(value, callback) {
99 | var command = that.getWriteCommand(deviceSid, value);
100 | if(that.platform.ConfigUtil.getAccessoryIgnoreWriteResult(deviceSid, that.accessoryType)) {
101 | that.platform.sendWriteCommandWithoutFeedback(deviceSid, command);
102 | that.callback2HB(deviceSid, this, callback, null);
103 | } else {
104 | that.platform.sendWriteCommand(deviceSid, command).then(result => {
105 | that.callback2HB(deviceSid, this, callback, null);
106 | }).catch(function(err) {
107 | that.platform.log.error(err);
108 | that.callback2HB(deviceSid, this, callback, err);
109 | });
110 | }
111 | });
112 | }
113 | }
114 | }
115 | }
116 |
117 | class DuplexSwitchSwitchLeftParser extends DuplexSwitchSwitchBaseParser {
118 | getOnCharacteristicValue(jsonObj, defaultValue) {
119 | var value = this.getValueFrJsonObjData(jsonObj, 'channel_0');
120 | if(value === 'on') {
121 | return true;
122 | } else if(value === 'off') {
123 | return false;
124 | } else {
125 | return defaultValue;
126 | }
127 | }
128 |
129 | getWriteCommand(deviceSid, value) {
130 | var model = this.platform.getDeviceModelBySid(deviceSid);
131 | var command = null;
132 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(deviceSid));
133 | if(1 == proto_version_prefix) {
134 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","data":{"channel_0":"' + (value ? 'on' : 'off') + '", "key": "${key}"}}';
135 | } else if(2 == proto_version_prefix) {
136 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","params":[{"channel_0":"' + (value ? 'on' : 'off') + '"}], "key": "${key}"}';
137 | } else {
138 | }
139 |
140 | return command;
141 | }
142 | }
143 |
144 | class DuplexSwitchSwitchRightParser extends DuplexSwitchSwitchBaseParser {
145 | getOnCharacteristicValue(jsonObj, defaultValue) {
146 | var value = this.getValueFrJsonObjData(jsonObj, 'channel_1');
147 | if(value === 'on') {
148 | return true;
149 | } else if(value === 'off') {
150 | return false;
151 | } else {
152 | return defaultValue;
153 | }
154 | }
155 |
156 | getWriteCommand(deviceSid, value) {
157 | var model = this.platform.getDeviceModelBySid(deviceSid);
158 | var command = null;
159 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(deviceSid));
160 | if(1 == proto_version_prefix) {
161 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","data":{"channel_1":"' + (value ? 'on' : 'off') + '", "key": "${key}"}"}';
162 | } else if(2 == proto_version_prefix) {
163 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","params":[{"channel_1":"' + (value ? 'on' : 'off') + '"}], "key": "${key}"}';
164 | } else {
165 | }
166 | return command;
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/parser/DuplexSwitchLNParser.js:
--------------------------------------------------------------------------------
1 | const DeviceParser = require('./DeviceParser');
2 | const AccessoryParser = require('./AccessoryParser');
3 |
4 | class DuplexSwitchLNParser extends DeviceParser {
5 | constructor(platform) {
6 | super(platform);
7 | }
8 |
9 | getAccessoriesParserInfo() {
10 | return {
11 | 'DuplexSwitchLN_Switch_Left': DuplexSwitchLNSwitchLeftParser,
12 | 'DuplexSwitchLN_Switch_Right': DuplexSwitchLNSwitchRightParser
13 | }
14 | }
15 | }
16 | DuplexSwitchLNParser.modelName = ['ctrl_ln2', 'ctrl_ln2.aq1'];
17 | module.exports = DuplexSwitchLNParser;
18 |
19 | class DuplexSwitchLNSwitchBaseParser extends AccessoryParser {
20 | constructor(platform, accessoryType) {
21 | super(platform, accessoryType)
22 | }
23 |
24 | getAccessoryCategory(deviceSid) {
25 | var serviceType = this.platform.ConfigUtil.getAccessoryServiceType(deviceSid, this.accessoryType);
26 | if(serviceType == 'Lightbulb') {
27 | return this.Accessory.Categories.LIGHTBULB;
28 | } else {
29 | return this.Accessory.Categories.SWITCH;
30 | }
31 | }
32 |
33 | getAccessoryInformation(deviceSid) {
34 | return {
35 | 'Manufacturer': 'Aqara',
36 | 'Model': 'Duplex Switch LN',
37 | 'SerialNumber': deviceSid
38 | };
39 | }
40 |
41 | getServices(jsonObj, accessoryName) {
42 | var that = this;
43 | var result = [];
44 |
45 | var service = null;
46 | var deviceSid = jsonObj['sid'];
47 | var serviceType = that.platform.ConfigUtil.getAccessoryServiceType(deviceSid, that.accessoryType);
48 | if(serviceType == 'Lightbulb') {
49 | service = new that.Service.Lightbulb(accessoryName);
50 | } else {
51 | service = new that.Service.Switch(accessoryName);
52 | }
53 | service.getCharacteristic(that.Characteristic.On);
54 | result.push(service);
55 |
56 | return result;
57 | }
58 |
59 | parserAccessories(jsonObj) {
60 | var that = this;
61 | var deviceSid = jsonObj['sid'];
62 | var uuid = that.getAccessoryUUID(deviceSid);
63 | var accessory = that.platform.AccessoryUtil.getByUUID(uuid);
64 | if(accessory) {
65 | var service = null;
66 | var serviceType = that.platform.ConfigUtil.getAccessoryServiceType(deviceSid, that.accessoryType);
67 | if(serviceType == 'Lightbulb') {
68 | service = accessory.getService(that.Service.Lightbulb);
69 | } else {
70 | service = accessory.getService(that.Service.Switch);
71 | }
72 | var onCharacteristic = service.getCharacteristic(that.Characteristic.On);
73 | var value = that.getOnCharacteristicValue(jsonObj, null);
74 | if(null != value) {
75 | onCharacteristic.updateValue(value);
76 | }
77 |
78 | if(that.platform.ConfigUtil.getAccessorySyncValue(deviceSid, that.accessoryType)) {
79 | if (onCharacteristic.listeners('get').length == 0) {
80 | onCharacteristic.on("get", function(callback) {
81 | var command = '{"cmd":"read", "sid":"' + deviceSid + '"}';
82 | that.platform.sendReadCommand(deviceSid, command).then(result => {
83 | var value = that.getOnCharacteristicValue(result, null);
84 | if(null != value) {
85 | callback(null, value);
86 | } else {
87 | callback(new Error('get value fail: ' + result));
88 | }
89 | }).catch(function(err) {
90 | that.platform.log.error(err);
91 | callback(err);
92 | });
93 | });
94 | }
95 | }
96 |
97 | if(onCharacteristic.listeners('set').length == 0) {
98 | onCharacteristic.on("set", function(value, callback) {
99 | var command = that.getWriteCommand(deviceSid, value);
100 | if(that.platform.ConfigUtil.getAccessoryIgnoreWriteResult(deviceSid, that.accessoryType)) {
101 | that.platform.sendWriteCommandWithoutFeedback(deviceSid, command);
102 | that.callback2HB(deviceSid, this, callback, null);
103 | } else {
104 | that.platform.sendWriteCommand(deviceSid, command).then(result => {
105 | that.callback2HB(deviceSid, this, callback, null);
106 | }).catch(function(err) {
107 | that.platform.log.error(err);
108 | that.callback2HB(deviceSid, this, callback, err);
109 | });
110 | }
111 | });
112 | }
113 | }
114 | }
115 | }
116 |
117 | class DuplexSwitchLNSwitchLeftParser extends DuplexSwitchLNSwitchBaseParser {
118 | getOnCharacteristicValue(jsonObj, defaultValue) {
119 | var value = this.getValueFrJsonObjData(jsonObj, 'channel_0');
120 | if(value === 'on') {
121 | return true;
122 | } else if(value === 'off') {
123 | return false;
124 | } else {
125 | return defaultValue;
126 | }
127 | }
128 |
129 | getWriteCommand(deviceSid, value) {
130 | var model = this.platform.getDeviceModelBySid(deviceSid);
131 | var command = null;
132 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(deviceSid));
133 | if(1 == proto_version_prefix) {
134 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","data":{"channel_0":"' + (value ? 'on' : 'off') + '", "key": "${key}"}}';
135 | } else if(2 == proto_version_prefix) {
136 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","params":[{"channel_0":"' + (value ? 'on' : 'off') + '"}], "key": "${key}"}';
137 | } else {
138 | }
139 |
140 | return command;
141 | }
142 | }
143 |
144 | class DuplexSwitchLNSwitchRightParser extends DuplexSwitchLNSwitchBaseParser {
145 | getOnCharacteristicValue(jsonObj, defaultValue) {
146 | var value = this.getValueFrJsonObjData(jsonObj, 'channel_1');
147 | if(value === 'on') {
148 | return true;
149 | } else if(value === 'off') {
150 | return false;
151 | } else {
152 | return defaultValue;
153 | }
154 | }
155 |
156 | getWriteCommand(deviceSid, value) {
157 | var model = this.platform.getDeviceModelBySid(deviceSid);
158 | var command = null;
159 | var proto_version_prefix = this.platform.getProtoVersionPrefixByProtoVersion(this.platform.getDeviceProtoVersionBySid(deviceSid));
160 | if(1 == proto_version_prefix) {
161 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","data":{"channel_1":"' + (value ? 'on' : 'off') + '", "key": "${key}"}}';
162 | } else if(2 == proto_version_prefix) {
163 | command = '{"cmd":"write","model":"' + model + '","sid":"' + deviceSid + '","params":[{"channel_1":"' + (value ? 'on' : 'off') + '"}], "key": "${key}"}';
164 | } else {
165 | }
166 |
167 | return command;
168 | }
169 | }
170 |
--------------------------------------------------------------------------------