Skip to content

Commit f665eba

Browse files
committed
Added support for Xiaomi zigbee plug
1 parent 89a75e0 commit f665eba

File tree

2 files changed

+92
-23
lines changed

2 files changed

+92
-23
lines changed

README.md

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
# org.openhab.binding.xiaomigateway
22

33
This binding brings Xiaomi Gateway Smart Home devices (Aqara) integration with OpenHAB1.x
4-
Currently only one gateway is supported and only getting sub device state/reading events confirmed to be working including the magic cube.
5-
Controlling of gateway light works too including color and brightness change within OpenHAB.
6-
Unfortunately I have no switch to test controlling its state using write command, but write key generation based on gateway token seems to be implemented OK.
4+
Currently only one gateway is supported.
5+
6+
Supported devices:
7+
- gateway light (including color and brightness change)
8+
- magnet sensor (door sensor)
9+
- motion sensor
10+
- temperature & humidity sensor
11+
- button (simple round switch)
12+
- plug (zigbee version, no reporting of power consumtion, only ON/OFF and if device in use)
13+
- magic cube (all events)
14+
15+
Unfortunately I have no aqara switch to test controlling its state using write command, but write key generation based on gateway token seems to be implemented OK.
716

817
Based on info found here: https://github.com/louisZL/lumi-gateway-local-api
918

@@ -61,6 +70,8 @@ Number RoomHumidity "Humidity [%.1f %%]" <humidity> { xiaomigateway="158d00011
6170
Switch XiaomiGatewayLight "Gateway light" { xiaomigateway="f1b5299a55e5.color" }
6271
Color XiaomiGatewayLightColor "Gateway light color" { xiaomigateway="f1b5299a55e5.color" }
6372
Dimmer XiaomiGatewayBrightness "Gateway brightness" { xiaomigateway="f1b5299a55e5.brightness" }
73+
Switch XiaomiPlug "Xiaomi zigbee plug" { xiaomigateway="158d00012944b3.plug" }
74+
Switch XiaomiPlugInUse "Xiaomi zigbee plug in use" { xiaomigateway="158d00012944b3.inuse" }
6475
```
6576
not tested, but should work - ___send ON command to these items to fire an event___
6677
```

src/main/java/org/openhab/binding/xiaomigateway/internal/XiaomiGatewayBinding.java

+78-20
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ private void receiveData(MulticastSocket socket, DatagramPacket dgram) {
178178
String sentence = new String(dgram.getData(), 0,
179179
dgram.getLength());
180180

181-
if (sentence.contains("\"voltage\"") || sentence.contains("\"mid\""))
181+
if (sentence.contains("\"plug\"") || sentence.contains("\"voltage\"") || sentence.contains("\"mid\""))
182182
logger.info("Received packet: " + sentence);
183183
else
184184
logger.debug("Received packet: " + sentence);
@@ -238,20 +238,19 @@ private void processEvent(XiaomiGatewayBindingProvider provider, String itemName
238238
String type = provider.getItemType(itemName);
239239
String eventSid = jobject.get("sid").getAsString();
240240

241-
if (!(type.startsWith(eventSid) && type.contains(".") ))
241+
if (!(type.startsWith(eventSid) && type.contains(".")))
242242
return;
243243

244244
String subType = type.split("\\.")[1];
245-
switch(subType)
246-
{
245+
switch (subType) {
247246
case "temperature":
248-
if( isTemperatureEvent(jobject) ) {
247+
if (isTemperatureEvent(jobject)) {
249248
logger.debug("Processing temperature event");
250249
processTemperatureEvent(itemName, jobject);
251250
}
252251
break;
253252
case "humidity":
254-
if(isHumidityEvent(jobject)) {
253+
if (isHumidityEvent(jobject)) {
255254
logger.debug("Processing humidity event");
256255
processHumidityEvent(itemName, jobject);
257256
}
@@ -265,47 +264,59 @@ private void processEvent(XiaomiGatewayBindingProvider provider, String itemName
265264
processColorEvent(itemName, jobject);
266265
break;
267266
case "virtual_switch":
268-
if( isButtonEvent(jobject, "click") ) {
267+
if (isButtonEvent(jobject, "click")) {
269268
logger.debug("Processing virtual switch click event");
270269
processVirtualSwitchEvent(itemName);
271270
}
272271
break;
273272
case "click":
274-
if(isButtonEvent(jobject, "click")) {
273+
if (isButtonEvent(jobject, "click")) {
275274
logger.debug("Processing click event");
276275
eventPublisher.sendCommand(itemName, OnOffType.ON);
277276
}
278277
break;
279278
case "double_click":
280-
if(isButtonEvent(jobject, "double_click") ) {
279+
if (isButtonEvent(jobject, "double_click")) {
281280
logger.debug("Processing double click event");
282281
eventPublisher.sendCommand(itemName, OnOffType.ON);
283282
}
284283
break;
285284
case "long_click":
286-
if( isButtonEvent(jobject, "long_click_press") ) {
285+
if (isButtonEvent(jobject, "long_click_press")) {
287286
logger.debug("Processing long click event");
288287
eventPublisher.sendCommand(itemName, OnOffType.ON);
289288
}
290289
break;
291290
case "long_click_release":
292-
if( isButtonEvent(jobject, "long_click_release")) {
291+
if (isButtonEvent(jobject, "long_click_release")) {
293292
logger.debug("Processing long click release event");
294293
eventPublisher.sendCommand(itemName, OnOffType.ON);
295294
}
296295
break;
297296
case "magnet":
298-
if(isMagnetEvent(jobject)) {
297+
if (isMagnetEvent(jobject)) {
299298
logger.debug("Processing magnet event");
300299
processMagnetEvent(itemName, jobject);
301300
}
302301
break;
303302
case "motion":
304-
if(isMotionEvent(jobject)) {
303+
if (isMotionEvent(jobject)) {
305304
logger.debug("Processing motion event");
306305
processMotionEvent(itemName, jobject);
307306
}
308307
break;
308+
case "plug":
309+
if (isPlugEvent(jobject)) {
310+
logger.debug("Processing plug event");
311+
processPlugEvent(itemName, jobject);
312+
}
313+
break;
314+
case "inuse":
315+
if (isPlugEvent(jobject)) {
316+
logger.debug("Processing plug inuse event");
317+
processPlugInuseEvent(itemName, jobject);
318+
}
319+
break;
309320
default:
310321
if (isCubeEvent(jobject)) {
311322
processCubeEvent(itemName, type, jobject);
@@ -424,11 +435,15 @@ private String getStatusEvent(JsonObject jobject) {
424435
}
425436

426437
private boolean isCubeEvent(JsonObject jobject) {
427-
return jobject != null && !jobject.isJsonNull() && jobject.get("model").getAsString().equals("cube");
438+
return jobject != null && jobject.has("model") && jobject.get("model").getAsString().equals("cube");
428439
}
429440

430441
private boolean isMotionEvent(JsonObject jobject) {
431-
return jobject != null && !jobject.isJsonNull() && jobject.get("model").getAsString().equals("motion");
442+
return jobject != null && jobject.has("model") && jobject.get("model").getAsString().equals("motion");
443+
}
444+
445+
private boolean isPlugEvent(JsonObject jobject) {
446+
return jobject != null && jobject.has("model") && jobject.get("model").getAsString().equals("plug");
432447
}
433448

434449
private void getGatewayInfo(JsonObject jobject) {
@@ -464,7 +479,7 @@ private void listDevice(JsonObject jobject) {
464479
private void processMotionEvent(String itemName, JsonObject jobject) {
465480
String data = jobject.get("data").getAsString();
466481
JsonObject jo = parser.parse(data).getAsJsonObject();
467-
String stat = (jo.get("status") != null) ? jo.get("status").getAsString().toLowerCase() : "no_motion";
482+
String stat = (jo.has("status")) ? jo.get("status").getAsString().toLowerCase() : "no_motion";
468483
State oldValue;
469484
try {
470485
oldValue = itemRegistry.getItem(itemName).getState();
@@ -476,6 +491,46 @@ private void processMotionEvent(String itemName, JsonObject jobject) {
476491
}
477492
}
478493

494+
private void processPlugEvent(String itemName, JsonObject jobject) {
495+
String data = jobject.get("data").getAsString();
496+
JsonObject jo = parser.parse(data).getAsJsonObject();
497+
String stat = (jo.has("status")) ? jo.get("status").getAsString().toLowerCase() : "off";
498+
State oldValue;
499+
try {
500+
oldValue = itemRegistry.getItem(itemName).getState();
501+
State newValue = stat.equals("on") ? OnOffType.ON : OnOffType.OFF;
502+
if (!newValue.equals(oldValue) || newValue.equals(OnOffType.ON))
503+
eventPublisher.postUpdate(itemName, newValue);
504+
} catch (ItemNotFoundException e) {
505+
logger.error(e.toString());
506+
}
507+
}
508+
509+
private void processPlugInuseEvent(String itemName, JsonObject jobject) {
510+
String data = jobject.get("data").getAsString();
511+
JsonObject jo = parser.parse(data).getAsJsonObject();
512+
State newValue;
513+
if (jo.has("inuse") ) {
514+
newValue = (jo.get("inuse").getAsString().equals("1")) ? OnOffType.ON : OnOffType.OFF;
515+
} else {
516+
if (jo.has("status") && jo.get("status").getAsString().toLowerCase().equals("off")) {
517+
//If power is off, in use is off too
518+
newValue = OnOffType.OFF;
519+
}
520+
else
521+
return;
522+
}
523+
524+
State oldValue;
525+
try {
526+
oldValue = itemRegistry.getItem(itemName).getState();
527+
if (!newValue.equals(oldValue) || newValue.equals(OnOffType.ON))
528+
eventPublisher.postUpdate(itemName, newValue);
529+
} catch (ItemNotFoundException e) {
530+
logger.error(e.toString());
531+
}
532+
}
533+
479534
private void processVirtualSwitchEvent(String itemName) {
480535
State oldValue;
481536
Command command = OnOffType.OFF;
@@ -557,7 +612,7 @@ private boolean isHumidityEvent(JsonObject jobject) {
557612
}
558613

559614
private Float formatValue(String value) {
560-
return Float.parseFloat(value.substring(0, value.length() - 2) + "." + value.substring(2));
615+
return Float.parseFloat(value.substring(0, value.length() - 2) + "." + value.substring(2));
561616
}
562617

563618
/**
@@ -740,8 +795,8 @@ protected void internalReceiveCommand(String itemName, Command command) {
740795
logger.error("Only OnOff/HSB/Percent command types currently supported");
741796
return;
742797
}
743-
if (!(itemType.contains("channel") || itemType.endsWith(".color") || itemType.endsWith(".brightness"))) {
744-
//only channel items
798+
if (!(itemType.contains("channel") || itemType.endsWith(".color") || itemType.endsWith(".brightness") || itemType.endsWith(".plug"))) {
799+
//only channel/plug items
745800
return;
746801
}
747802

@@ -765,7 +820,10 @@ protected void internalReceiveCommand(String itemName, Command command) {
765820
return;
766821
}
767822

768-
if (itemType.endsWith(".channel_0") || itemType.endsWith(".channel_1")) {
823+
if (itemType.endsWith(".plug")) {
824+
String sid = getItemSid(itemType);
825+
requestWrite(sid, new String[]{"status"}, new Object[]{command.toString().toLowerCase()});
826+
} else if (itemType.endsWith(".channel_0") || itemType.endsWith(".channel_1")) {
769827
//86ctrl_neutral1/2
770828
String sid = getItemSid(itemType);
771829
String channel = getItemChannel(itemType);

0 commit comments

Comments
 (0)