homebridge-gree-ac 1.0.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/LICENSE +176 -21
- package/README.md +180 -42
- package/config.schema.json +277 -0
- package/dist/commands.d.ts +121 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +123 -0
- package/dist/commands.js.map +1 -0
- package/dist/crypto.d.ts +6 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +19 -0
- package/dist/crypto.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/platform.d.ts +35 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +203 -0
- package/dist/platform.js.map +1 -0
- package/dist/platformAccessory.d.ts +89 -0
- package/dist/platformAccessory.d.ts.map +1 -0
- package/dist/platformAccessory.js +867 -0
- package/dist/platformAccessory.js.map +1 -0
- package/dist/settings.d.ts +51 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +50 -0
- package/dist/settings.js.map +1 -0
- package/dist/tsAccessory.d.ts +36 -0
- package/dist/tsAccessory.d.ts.map +1 -0
- package/dist/tsAccessory.js +65 -0
- package/dist/tsAccessory.js.map +1 -0
- package/greedevice.jpg +0 -0
- package/greemac.jpg +0 -0
- package/package.json +51 -23
- package/uiconfig.jpg +0 -0
- package/.idea/homebridge-gree-ac.iml +0 -12
- package/.idea/misc.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
- package/.idea/workspace.xml +0 -208
- package/app/commandEnums.js +0 -135
- package/app/deviceFactory.js +0 -306
- package/app/encryptionService.js +0 -39
- package/example.config.json +0 -28
- package/index.js +0 -373
package/.idea/workspace.xml
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ChangeListManager">
|
|
4
|
-
<list default="true" id="0423c35f-7832-4046-80c6-ba4b18f972ef" name="Default" comment="">
|
|
5
|
-
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
|
6
|
-
<change beforePath="$PROJECT_DIR$/app/deviceFactory.js" beforeDir="false" afterPath="$PROJECT_DIR$/app/deviceFactory.js" afterDir="false" />
|
|
7
|
-
<change beforePath="$PROJECT_DIR$/example.config.json" beforeDir="false" afterPath="$PROJECT_DIR$/example.config.json" afterDir="false" />
|
|
8
|
-
<change beforePath="$PROJECT_DIR$/package-lock.json" beforeDir="false" />
|
|
9
|
-
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
|
|
10
|
-
</list>
|
|
11
|
-
<ignored path="$PROJECT_DIR$/.tmp/" />
|
|
12
|
-
<ignored path="$PROJECT_DIR$/temp/" />
|
|
13
|
-
<ignored path="$PROJECT_DIR$/tmp/" />
|
|
14
|
-
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
|
15
|
-
<option name="TRACKING_ENABLED" value="true" />
|
|
16
|
-
<option name="SHOW_DIALOG" value="false" />
|
|
17
|
-
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
18
|
-
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
19
|
-
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
20
|
-
</component>
|
|
21
|
-
<component name="FileEditorManager">
|
|
22
|
-
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300" />
|
|
23
|
-
</component>
|
|
24
|
-
<component name="FindInProjectRecents">
|
|
25
|
-
<findStrings>
|
|
26
|
-
<find>console.</find>
|
|
27
|
-
<find>log</find>
|
|
28
|
-
</findStrings>
|
|
29
|
-
</component>
|
|
30
|
-
<component name="Git.Settings">
|
|
31
|
-
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
32
|
-
</component>
|
|
33
|
-
<component name="IdeDocumentHistory">
|
|
34
|
-
<option name="CHANGED_PATHS">
|
|
35
|
-
<list>
|
|
36
|
-
<option value="$PROJECT_DIR$/app/deviceFactory.js" />
|
|
37
|
-
<option value="$PROJECT_DIR$/index.js" />
|
|
38
|
-
<option value="$PROJECT_DIR$/package.json" />
|
|
39
|
-
<option value="$PROJECT_DIR$/example.config.json" />
|
|
40
|
-
</list>
|
|
41
|
-
</option>
|
|
42
|
-
</component>
|
|
43
|
-
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
|
|
44
|
-
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
|
|
45
|
-
<component name="JsGulpfileManager">
|
|
46
|
-
<detection-done>true</detection-done>
|
|
47
|
-
<sorting>DEFINITION_ORDER</sorting>
|
|
48
|
-
</component>
|
|
49
|
-
<component name="NodePackageJsonFileManager">
|
|
50
|
-
<packageJsonPaths>
|
|
51
|
-
<path value="$PROJECT_DIR$/package.json" />
|
|
52
|
-
</packageJsonPaths>
|
|
53
|
-
</component>
|
|
54
|
-
<component name="PackageJsonUpdateNotifier">
|
|
55
|
-
<dismissed value="$PROJECT_DIR$/package.json" />
|
|
56
|
-
</component>
|
|
57
|
-
<component name="ProjectFrameBounds">
|
|
58
|
-
<option name="y" value="22" />
|
|
59
|
-
<option name="width" value="1280" />
|
|
60
|
-
<option name="height" value="700" />
|
|
61
|
-
</component>
|
|
62
|
-
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
|
63
|
-
<component name="ProjectView">
|
|
64
|
-
<navigator proportions="" version="1">
|
|
65
|
-
<foldersAlwaysOnTop value="true" />
|
|
66
|
-
</navigator>
|
|
67
|
-
<panes>
|
|
68
|
-
<pane id="ProjectPane">
|
|
69
|
-
<subPane>
|
|
70
|
-
<expand>
|
|
71
|
-
<path>
|
|
72
|
-
<item name="homebridge-gree-ac" type="b2602c69:ProjectViewProjectNode" />
|
|
73
|
-
<item name="homebridge-gree-ac" type="462c0819:PsiDirectoryNode" />
|
|
74
|
-
</path>
|
|
75
|
-
</expand>
|
|
76
|
-
<select />
|
|
77
|
-
</subPane>
|
|
78
|
-
</pane>
|
|
79
|
-
<pane id="Scope" />
|
|
80
|
-
</panes>
|
|
81
|
-
</component>
|
|
82
|
-
<component name="PropertiesComponent">
|
|
83
|
-
<property name="WebServerToolWindowFactoryState" value="false" />
|
|
84
|
-
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
|
85
|
-
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
|
86
|
-
<property name="nodejs_package_manager_path" value="npm" />
|
|
87
|
-
</component>
|
|
88
|
-
<component name="RunDashboard">
|
|
89
|
-
<option name="ruleStates">
|
|
90
|
-
<list>
|
|
91
|
-
<RuleState>
|
|
92
|
-
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
|
93
|
-
</RuleState>
|
|
94
|
-
<RuleState>
|
|
95
|
-
<option name="name" value="StatusDashboardGroupingRule" />
|
|
96
|
-
</RuleState>
|
|
97
|
-
</list>
|
|
98
|
-
</option>
|
|
99
|
-
</component>
|
|
100
|
-
<component name="RunManager">
|
|
101
|
-
<configuration name="index.js" type="NodeJSConfigurationType" factoryName="Node.js" temporary="true" nameIsGenerated="true" path-to-js-file="index.js" working-dir="$PROJECT_DIR$" />
|
|
102
|
-
<recent_temporary>
|
|
103
|
-
<list>
|
|
104
|
-
<item itemvalue="Node.js.index.js" />
|
|
105
|
-
</list>
|
|
106
|
-
</recent_temporary>
|
|
107
|
-
</component>
|
|
108
|
-
<component name="SvnConfiguration">
|
|
109
|
-
<configuration />
|
|
110
|
-
</component>
|
|
111
|
-
<component name="TaskManager">
|
|
112
|
-
<task active="true" id="Default" summary="Default task">
|
|
113
|
-
<changelist id="0423c35f-7832-4046-80c6-ba4b18f972ef" name="Default" comment="" />
|
|
114
|
-
<created>1531201922723</created>
|
|
115
|
-
<option name="number" value="Default" />
|
|
116
|
-
<option name="presentableId" value="Default" />
|
|
117
|
-
<updated>1531201922723</updated>
|
|
118
|
-
<workItem from="1531201926328" duration="353000" />
|
|
119
|
-
<workItem from="1531401617854" duration="199000" />
|
|
120
|
-
</task>
|
|
121
|
-
<servers />
|
|
122
|
-
</component>
|
|
123
|
-
<component name="TimeTrackingManager">
|
|
124
|
-
<option name="totallyTimeSpent" value="552000" />
|
|
125
|
-
</component>
|
|
126
|
-
<component name="ToolWindowManager">
|
|
127
|
-
<frame x="0" y="22" width="1280" height="700" extended-state="0" />
|
|
128
|
-
<layout>
|
|
129
|
-
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.19936457" />
|
|
130
|
-
<window_info anchor="bottom" id="TODO" order="6" />
|
|
131
|
-
<window_info anchor="bottom" id="Docker" order="7" show_stripe_button="false" />
|
|
132
|
-
<window_info anchor="bottom" id="Event Log" order="7" side_tool="true" />
|
|
133
|
-
<window_info anchor="bottom" id="Version Control" order="7" />
|
|
134
|
-
<window_info anchor="bottom" id="Run" order="2" weight="0.3290735" />
|
|
135
|
-
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
|
|
136
|
-
<window_info anchor="bottom" id="Terminal" order="7" />
|
|
137
|
-
<window_info id="Favorites" order="2" side_tool="true" />
|
|
138
|
-
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
|
139
|
-
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
|
140
|
-
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
|
141
|
-
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
|
|
142
|
-
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
|
143
|
-
<window_info anchor="bottom" id="Message" order="0" />
|
|
144
|
-
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
|
145
|
-
<window_info anchor="bottom" id="Find" order="1" />
|
|
146
|
-
</layout>
|
|
147
|
-
</component>
|
|
148
|
-
<component name="TypeScriptGeneratedFilesManager">
|
|
149
|
-
<option name="version" value="1" />
|
|
150
|
-
</component>
|
|
151
|
-
<component name="VcsContentAnnotationSettings">
|
|
152
|
-
<option name="myLimit" value="2678400000" />
|
|
153
|
-
</component>
|
|
154
|
-
<component name="editorHistoryManager">
|
|
155
|
-
<entry file="file://$PROJECT_DIR$/index.js">
|
|
156
|
-
<provider selected="true" editor-type-id="text-editor">
|
|
157
|
-
<state relative-caret-position="5370">
|
|
158
|
-
<caret line="358" column="27" lean-forward="true" selection-start-line="358" selection-start-column="27" selection-end-line="358" selection-end-column="27" />
|
|
159
|
-
</state>
|
|
160
|
-
</provider>
|
|
161
|
-
</entry>
|
|
162
|
-
<entry file="file://$PROJECT_DIR$/app/deviceFactory.js">
|
|
163
|
-
<provider selected="true" editor-type-id="text-editor">
|
|
164
|
-
<state relative-caret-position="735">
|
|
165
|
-
<caret line="49" lean-forward="true" selection-start-line="49" selection-end-line="49" />
|
|
166
|
-
</state>
|
|
167
|
-
</provider>
|
|
168
|
-
</entry>
|
|
169
|
-
<entry file="file://$PROJECT_DIR$/package-lock.json">
|
|
170
|
-
<provider selected="true" editor-type-id="text-editor" />
|
|
171
|
-
</entry>
|
|
172
|
-
<entry file="file://$PROJECT_DIR$/example.config.json">
|
|
173
|
-
<provider selected="true" editor-type-id="text-editor">
|
|
174
|
-
<state relative-caret-position="165">
|
|
175
|
-
<caret line="11" column="32" lean-forward="true" selection-start-line="11" selection-start-column="32" selection-end-line="11" selection-end-column="32" />
|
|
176
|
-
</state>
|
|
177
|
-
</provider>
|
|
178
|
-
</entry>
|
|
179
|
-
<entry file="file://$PROJECT_DIR$/app/deviceFactory.js">
|
|
180
|
-
<provider selected="true" editor-type-id="text-editor">
|
|
181
|
-
<state relative-caret-position="735">
|
|
182
|
-
<caret line="49" selection-start-line="49" selection-end-line="49" />
|
|
183
|
-
</state>
|
|
184
|
-
</provider>
|
|
185
|
-
</entry>
|
|
186
|
-
<entry file="file://$PROJECT_DIR$/package.json">
|
|
187
|
-
<provider selected="true" editor-type-id="text-editor">
|
|
188
|
-
<state relative-caret-position="345">
|
|
189
|
-
<caret line="23" lean-forward="true" selection-start-line="23" selection-end-line="23" />
|
|
190
|
-
</state>
|
|
191
|
-
</provider>
|
|
192
|
-
</entry>
|
|
193
|
-
<entry file="file://$PROJECT_DIR$/index.js">
|
|
194
|
-
<provider selected="true" editor-type-id="text-editor">
|
|
195
|
-
<state relative-caret-position="1758">
|
|
196
|
-
<caret line="354" column="6" lean-forward="true" selection-start-line="354" selection-start-column="6" selection-end-line="354" selection-end-column="6" />
|
|
197
|
-
</state>
|
|
198
|
-
</provider>
|
|
199
|
-
</entry>
|
|
200
|
-
<entry file="file://$PROJECT_DIR$/README.md">
|
|
201
|
-
<provider selected="true" editor-type-id="text-editor">
|
|
202
|
-
<state relative-caret-position="90">
|
|
203
|
-
<caret line="6" column="63" lean-forward="true" selection-start-line="6" selection-start-column="63" selection-end-line="6" selection-end-column="63" />
|
|
204
|
-
</state>
|
|
205
|
-
</provider>
|
|
206
|
-
</entry>
|
|
207
|
-
</component>
|
|
208
|
-
</project>
|
package/app/commandEnums.js
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
// power state of the device
|
|
3
|
-
power: {
|
|
4
|
-
code: 'Pow',
|
|
5
|
-
value: {
|
|
6
|
-
off: 0,
|
|
7
|
-
on: 1
|
|
8
|
-
}
|
|
9
|
-
},
|
|
10
|
-
// mode of operation
|
|
11
|
-
mode: {
|
|
12
|
-
code: 'Mod',
|
|
13
|
-
value: {
|
|
14
|
-
auto: 0,
|
|
15
|
-
cool: 1,
|
|
16
|
-
dry: 2,
|
|
17
|
-
fan: 3,
|
|
18
|
-
heat: 4
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
// temperature unit (must be together with set temperature)
|
|
22
|
-
temperatureUnit: {
|
|
23
|
-
code: 'TemUn',
|
|
24
|
-
value: {
|
|
25
|
-
celsius: 0,
|
|
26
|
-
fahrenheit: 1
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
// set temperature (must be together with temperature unit)
|
|
30
|
-
temperature: {
|
|
31
|
-
code: 'SetTem'
|
|
32
|
-
},
|
|
33
|
-
// fan speed
|
|
34
|
-
fanSpeed: {
|
|
35
|
-
code: 'WdSpd',
|
|
36
|
-
value: {
|
|
37
|
-
auto: 0,
|
|
38
|
-
low: 1,
|
|
39
|
-
mediumLow: 2, // not available on 3-speed units
|
|
40
|
-
medium: 3,
|
|
41
|
-
mediumHigh: 4, // not available on 3-speed units
|
|
42
|
-
high: 5
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
// fresh air valve
|
|
46
|
-
airVale: {
|
|
47
|
-
code: 'Air',
|
|
48
|
-
value: {
|
|
49
|
-
off: 0,
|
|
50
|
-
on: 1
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
// "Blow" or "X-Fan", this function keeps the fan running for a while after shutting down. Only usable in Dry and Cool mode
|
|
54
|
-
blow: {
|
|
55
|
-
code: 'Blo',
|
|
56
|
-
value: {
|
|
57
|
-
off: 0,
|
|
58
|
-
on: 1
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
// controls Health ("Cold plasma") mode, only for devices equipped with "anion generator", which absorbs dust and kills bacteria
|
|
62
|
-
health: {
|
|
63
|
-
code: 'Health',
|
|
64
|
-
value: {
|
|
65
|
-
off: 0,
|
|
66
|
-
on: 1
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
// sleep mode, which gradually changes the temperature in Cool, Heat and Dry mode
|
|
70
|
-
sleep: {
|
|
71
|
-
code: 'SwhSlp',
|
|
72
|
-
value: {
|
|
73
|
-
off: 0,
|
|
74
|
-
on: 1
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
// turns all indicators and the display on the unit on or off
|
|
78
|
-
lights: {
|
|
79
|
-
code: 'Lig',
|
|
80
|
-
value: {
|
|
81
|
-
off: 0,
|
|
82
|
-
on: 1
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
// controls the swing mode of the horizontal air blades (not available on all units)
|
|
86
|
-
swingHor: {
|
|
87
|
-
code: 'SwingLfRig',
|
|
88
|
-
value: {
|
|
89
|
-
default: 0
|
|
90
|
-
// TODO: remaining values
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
// controls the swing mode of the vertical air blades
|
|
94
|
-
swingVert: {
|
|
95
|
-
code: 'SwUpDn',
|
|
96
|
-
value: {
|
|
97
|
-
default: 0,
|
|
98
|
-
full: 1, // swing in full range
|
|
99
|
-
fixedTop: 2, // fixed in the upmost position (1/5)
|
|
100
|
-
fixedMidTop: 3, // fixed in the middle-up position (2/5)
|
|
101
|
-
fixedMid: 4, // fixed in the middle position (3/5)
|
|
102
|
-
fixedMidBottom: 5, // fixed in the middle-low position (4/5)
|
|
103
|
-
fixedBottom: 6, // fixed in the lowest position (5/5)
|
|
104
|
-
swingBottom: 7, // swing in the downmost region (5/5)
|
|
105
|
-
swingMidBottom: 8, // swing in the middle-low region (4/5)
|
|
106
|
-
swingMid: 9, // swing in the middle region (3/5)
|
|
107
|
-
swingMidTop: 10, // swing in the middle-up region (2/5)
|
|
108
|
-
swingTop: 11 // swing in the upmost region (1/5)
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
// controls the Quiet mode which slows down the fan to its most quiet speed. Not available in Dry and Fan mode
|
|
112
|
-
quiet: {
|
|
113
|
-
code: 'Quiet',
|
|
114
|
-
value: {
|
|
115
|
-
off: 0,
|
|
116
|
-
on: 1
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
// sets fan speed to the maximum. Fan speed cannot be changed while active and only available in Dry and Cool mode
|
|
120
|
-
turbo: {
|
|
121
|
-
code: 'Tur',
|
|
122
|
-
value: {
|
|
123
|
-
off: 0,
|
|
124
|
-
on: 1
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
// energy saving mode
|
|
128
|
-
energySave: {
|
|
129
|
-
code: 'SvSt',
|
|
130
|
-
value: {
|
|
131
|
-
off: 0,
|
|
132
|
-
on: 1
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
};
|
package/app/deviceFactory.js
DELETED
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
const dgram = require('dgram');
|
|
2
|
-
const encryptionService = require('./encryptionService')();
|
|
3
|
-
const cmd = require('./commandEnums');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Class representing a single connected device
|
|
7
|
-
*/
|
|
8
|
-
class Device {
|
|
9
|
-
// const socket = dgram.createSocket({type: 'udp4', reuseAddr: true});
|
|
10
|
-
/**
|
|
11
|
-
* Create device model and establish UDP connection with remote host
|
|
12
|
-
* @param {object} [options] Options
|
|
13
|
-
* @param {string} [options.address] HVAC IP address
|
|
14
|
-
* @callback [options.onStatus] Callback function run on each status update
|
|
15
|
-
* @callback [options.onUpdate] Callback function run after command
|
|
16
|
-
* @callback [options.onConnected] Callback function run once connection is established
|
|
17
|
-
*/
|
|
18
|
-
constructor(options) {
|
|
19
|
-
this.socket = dgram.createSocket({type: 'udp4', reuseAddr: true});
|
|
20
|
-
// Set defaults
|
|
21
|
-
this.options = {
|
|
22
|
-
host: options.host,
|
|
23
|
-
onStatus: options.onStatus || function() {},
|
|
24
|
-
onUpdate: options.onUpdate || function() {},
|
|
25
|
-
onConnected: options.onConnected || function() {},
|
|
26
|
-
onError: options.onError || function() {},
|
|
27
|
-
onDisconnected: options.onDisconnected || function() {},
|
|
28
|
-
updateInterval: options.updateInterval || 10000,
|
|
29
|
-
port: 8000 + parseInt(options.host.split('.')[3]),
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Device object
|
|
34
|
-
* @typedef {object} Device
|
|
35
|
-
* @property {string} id - ID
|
|
36
|
-
* @property {string} name - Name
|
|
37
|
-
* @property {string} address - IP address
|
|
38
|
-
* @property {number} port - Port number
|
|
39
|
-
* @property {boolean} bound - If is already bound
|
|
40
|
-
* @property {object} props - Properties
|
|
41
|
-
*/
|
|
42
|
-
var that = this;
|
|
43
|
-
|
|
44
|
-
// console.log("[GreeAC]: init deviceFactory on host %s [server port %s]", that.options.host, that.options.port);
|
|
45
|
-
|
|
46
|
-
that.device = {};
|
|
47
|
-
|
|
48
|
-
// Initialize connection and bind with device
|
|
49
|
-
that._connectToDevice(that.options.host, that.options.port);
|
|
50
|
-
|
|
51
|
-
// Handle incoming messages
|
|
52
|
-
this.socket.on('message', (msg, rinfo) => that._handleResponse(msg, rinfo));
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Initialize connection
|
|
57
|
-
* @param {string} address - IP/host address
|
|
58
|
-
*/
|
|
59
|
-
_connectToDevice(address, port) {
|
|
60
|
-
var that = this;
|
|
61
|
-
try {
|
|
62
|
-
this.socket.bind(port, "0.0.0.0", () => {
|
|
63
|
-
const message = new Buffer(JSON.stringify({t: 'scan'}));
|
|
64
|
-
this.socket.setBroadcast(false);
|
|
65
|
-
// console.log("[GreeAC]: connecting to %s [using source port %d]", address, port);
|
|
66
|
-
this.socket.send(message, 0, message.length, 7000, address);
|
|
67
|
-
});
|
|
68
|
-
} catch (err) {
|
|
69
|
-
// console.log("[GreeAC]: _connectToDevice error - port %d %s",port, err);
|
|
70
|
-
const timeout = 5
|
|
71
|
-
that.options.onDisconnected(that.device);
|
|
72
|
-
setTimeout(() => {
|
|
73
|
-
that._connectToDevice(address, port);
|
|
74
|
-
}, timeout * 1000);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Register new device locally
|
|
80
|
-
* @param {string} id - CID received in handshake message
|
|
81
|
-
* @param {string} name - Device name received in handshake message
|
|
82
|
-
* @param {string} address - IP/host address
|
|
83
|
-
* @param {number} port - Port number
|
|
84
|
-
*/
|
|
85
|
-
_setDevice (id, name, address, port) {
|
|
86
|
-
var that = this;
|
|
87
|
-
that.device.id = id;
|
|
88
|
-
that.device.name = name;
|
|
89
|
-
that.device.address = address;
|
|
90
|
-
that.device.port = port;
|
|
91
|
-
that.device.bound = false;
|
|
92
|
-
that.device.props = {};
|
|
93
|
-
// console.log('[GreeAC] New device added: %s - %s', that.device.name, that.device.address);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Send binding request to device
|
|
98
|
-
* @param {Device} device Device object
|
|
99
|
-
*/
|
|
100
|
-
_sendBindRequest(device) {
|
|
101
|
-
var that = this;
|
|
102
|
-
const message = {
|
|
103
|
-
mac: that.device.id,
|
|
104
|
-
t: 'bind',
|
|
105
|
-
uid: 0
|
|
106
|
-
};
|
|
107
|
-
const encryptedBoundMessage = encryptionService.encrypt(message);
|
|
108
|
-
const request = {
|
|
109
|
-
cid: 'app',
|
|
110
|
-
i: 1,
|
|
111
|
-
t: 'pack',
|
|
112
|
-
uid: 0,
|
|
113
|
-
pack: encryptedBoundMessage
|
|
114
|
-
};
|
|
115
|
-
const toSend = new Buffer(JSON.stringify(request));
|
|
116
|
-
this.socket.send(toSend, 0, toSend.length, device.port, device.address);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Confirm device is bound and update device status on list
|
|
121
|
-
* @param {String} id - Device ID
|
|
122
|
-
* @param {String} key - Encryption key
|
|
123
|
-
*/
|
|
124
|
-
_confirmBinding(id, key) {
|
|
125
|
-
var that = this;
|
|
126
|
-
that.device.bound = true;
|
|
127
|
-
that.device.key = key;
|
|
128
|
-
// console.log('[GreeAC] device is bound: %s - %s', that.device.name, that.device.key);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Confirm device is bound and update device status on list
|
|
133
|
-
* @param {Device} device - Device
|
|
134
|
-
*/
|
|
135
|
-
_requestDeviceStatus (device) {
|
|
136
|
-
var that = this;
|
|
137
|
-
const message = {
|
|
138
|
-
cols: Object.keys(cmd).map(key => cmd[key].code),
|
|
139
|
-
mac: device.id,
|
|
140
|
-
t: 'status'
|
|
141
|
-
};
|
|
142
|
-
that._sendRequest(message, device.address, device.port);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Handle UDP response from device
|
|
147
|
-
* @param {string} msg Serialized JSON string with message
|
|
148
|
-
* @param {object} rinfo Additional request information
|
|
149
|
-
* @param {string} rinfo.address IP/host address
|
|
150
|
-
* @param {number} rinfo.port Port number
|
|
151
|
-
*/
|
|
152
|
-
_handleResponse(msg, rinfo) {
|
|
153
|
-
var that = this;
|
|
154
|
-
if (rinfo.address != that.options.host) {
|
|
155
|
-
//console.log("We received response from %s but we are looking for %s",rinfo.address, that.options.host );
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const message = JSON.parse(msg + '');
|
|
159
|
-
try{
|
|
160
|
-
// Extract encrypted package from message using device key (if available)
|
|
161
|
-
const pack = encryptionService.decrypt(message, (that.device || {}).key);
|
|
162
|
-
// If package type is response to handshake
|
|
163
|
-
if (pack.t === 'dev') {
|
|
164
|
-
that._setDevice(message.cid, pack.name, rinfo.address, rinfo.port);
|
|
165
|
-
that._sendBindRequest(that.device);
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// If package type is binding confirmation
|
|
170
|
-
if (pack.t === 'bindok' && that.device.id) {
|
|
171
|
-
that._confirmBinding(message.cid, pack.key);
|
|
172
|
-
|
|
173
|
-
// Start requesting device status on set interval
|
|
174
|
-
setInterval(that._requestDeviceStatus.bind(this, that.device), that.options.updateInterval);
|
|
175
|
-
that.options.onConnected(that.device)
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// If package type is device status
|
|
180
|
-
if (pack.t === 'dat' && that.device.bound) {
|
|
181
|
-
pack.cols.forEach((col, i) => {
|
|
182
|
-
that.device.props[col] = pack.dat[i];
|
|
183
|
-
});
|
|
184
|
-
that.options.onStatus(that.device);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// If package type is response, update device properties
|
|
189
|
-
if (pack.t === 'res' && that.device.bound) {
|
|
190
|
-
pack.opt.forEach((opt, i) => {
|
|
191
|
-
that.device.props[opt] = pack.val[i];
|
|
192
|
-
});
|
|
193
|
-
that.options.onUpdate(that.device);
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
that.options.onError(that.device);
|
|
197
|
-
} catch (err) {
|
|
198
|
-
that.options.onError(that.device);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Send commands to a bound device
|
|
204
|
-
* @param {string[]} commands List of commands
|
|
205
|
-
* @param {number[]} values List of values
|
|
206
|
-
*/
|
|
207
|
-
_sendCommand (commands = [], values = []) {
|
|
208
|
-
var that = this;
|
|
209
|
-
const message = {
|
|
210
|
-
opt: commands,
|
|
211
|
-
p: values,
|
|
212
|
-
t: 'cmd'
|
|
213
|
-
};
|
|
214
|
-
that._sendRequest(message);
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Send request to a bound device
|
|
219
|
-
* @param {object} message
|
|
220
|
-
* @param {string[]} message.opt
|
|
221
|
-
* @param {number[]} message.p
|
|
222
|
-
* @param {string} message.t
|
|
223
|
-
* @param {string} [address] IP/host address
|
|
224
|
-
* @param {number} [port] Port number
|
|
225
|
-
*/
|
|
226
|
-
_sendRequest (message, address = this.device.address, port = this.device.port) {
|
|
227
|
-
var that = this;
|
|
228
|
-
const encryptedMessage = encryptionService.encrypt(message, this.device.key);
|
|
229
|
-
const request = {
|
|
230
|
-
cid: 'app',
|
|
231
|
-
i: 0,
|
|
232
|
-
t: 'pack',
|
|
233
|
-
uid: 0,
|
|
234
|
-
pack: encryptedMessage
|
|
235
|
-
};
|
|
236
|
-
const serializedRequest = new Buffer(JSON.stringify(request));
|
|
237
|
-
this.socket.send(serializedRequest, 0, serializedRequest.length, port, address);
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Turn on/off
|
|
242
|
-
* @param {boolean} value State
|
|
243
|
-
*/
|
|
244
|
-
setPower (value) {
|
|
245
|
-
var that = this;
|
|
246
|
-
that._sendCommand(
|
|
247
|
-
[cmd.power.code],
|
|
248
|
-
[value ? 1 : 0]
|
|
249
|
-
);
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Set temperature
|
|
254
|
-
* @param {number} value Temperature
|
|
255
|
-
* @param {number} [unit=0] Units (defaults to Celsius)
|
|
256
|
-
*/
|
|
257
|
-
setTemp (value, unit = cmd.temperatureUnit.value.celsius) {
|
|
258
|
-
var that = this;
|
|
259
|
-
that._sendCommand(
|
|
260
|
-
[cmd.temperatureUnit.code, cmd.temperature.code],
|
|
261
|
-
[unit, value]
|
|
262
|
-
);
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Set mode
|
|
267
|
-
* @param {number} value Mode value (0-4)
|
|
268
|
-
*/
|
|
269
|
-
setMode (value) {
|
|
270
|
-
var that = this;
|
|
271
|
-
that._sendCommand(
|
|
272
|
-
[cmd.mode.code],
|
|
273
|
-
[value]
|
|
274
|
-
);
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Set fan speed
|
|
279
|
-
* @param {number} value Fan speed value (0-5)
|
|
280
|
-
*/
|
|
281
|
-
setFanSpeed (value) {
|
|
282
|
-
var that = this;
|
|
283
|
-
that._sendCommand(
|
|
284
|
-
[cmd.fanSpeed.code],
|
|
285
|
-
[value]
|
|
286
|
-
);
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Set vertical swing
|
|
291
|
-
* @param {number} value Vertical swing value (0-11)
|
|
292
|
-
*/
|
|
293
|
-
setSwingVert (value) {
|
|
294
|
-
var that = this;
|
|
295
|
-
that._sendCommand(
|
|
296
|
-
[cmd.swingVert.code],
|
|
297
|
-
[value]
|
|
298
|
-
);
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
module.exports.connect = function(options) {
|
|
304
|
-
return new Device(options);
|
|
305
|
-
};
|
|
306
|
-
|
package/app/encryptionService.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const crypto = require('crypto');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Module containing encryption services
|
|
7
|
-
* @param {String} key AES general key
|
|
8
|
-
*/
|
|
9
|
-
module.exports = function(defaultKey = 'a3K8Bx%2r8Y7#xDh') {
|
|
10
|
-
const EncryptionService = {
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Decrypt UDP message
|
|
14
|
-
* @param {object} input Response object
|
|
15
|
-
* @param {string} input.pack Encrypted JSON string
|
|
16
|
-
* @param {string} [key] AES key
|
|
17
|
-
*/
|
|
18
|
-
decrypt: (input, key = defaultKey) => {
|
|
19
|
-
const decipher = crypto.createDecipheriv('aes-128-ecb', key, '');
|
|
20
|
-
const str = decipher.update(input.pack, 'base64', 'utf8');
|
|
21
|
-
const response = JSON.parse(str + decipher.final('utf8'));
|
|
22
|
-
return response;
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Encrypt UDP message
|
|
27
|
-
* @param {object} output Request object
|
|
28
|
-
* @param {string} [key] AES key
|
|
29
|
-
*/
|
|
30
|
-
encrypt: (output, key = defaultKey) => {
|
|
31
|
-
const cipher = crypto.createCipheriv('aes-128-ecb', key, '');
|
|
32
|
-
const str = cipher.update(JSON.stringify(output), 'utf8', 'base64');
|
|
33
|
-
const request = str + cipher.final('base64');
|
|
34
|
-
return request;
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
return EncryptionService;
|
|
39
|
-
};
|