Skip to content

Commit

Permalink
Merge pull request #39 from eperott/indicator_cc
Browse files Browse the repository at this point in the history
Add support for Indicator Command Class
  • Loading branch information
whizzosoftware authored May 13, 2019
2 parents c1ff0ac + a497a3d commit b5a3378
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 1 deletion.
14 changes: 13 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,19 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.24.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.12.0</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public static CommandClass createCommandClass(byte commandClassId) {
return new BinarySwitchCommandClass();
case ColorControlCommandClass.ID:
return new ColorControlCommandClass();
case IndicatorCommandClass.ID:
return new IndicatorCommandClass();
case ManufacturerSpecificCommandClass.ID:
return new ManufacturerSpecificCommandClass();
case MeterCommandClass.ID:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*******************************************************************************
* Copyright (c) 2019 Whizzo Software, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.whizzosoftware.wzwave.commandclass;

import com.whizzosoftware.wzwave.frame.DataFrame;
import com.whizzosoftware.wzwave.node.NodeContext;
import com.whizzosoftware.wzwave.util.ByteUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* IndicatorCommand Class
*
* @author Per Otterström
*/
public class IndicatorCommandClass extends CommandClass {
private final Logger logger = LoggerFactory.getLogger(getClass());

public static final byte INDICATOR_SET = 0x01;
public static final byte INDICATOR_GET = 0x02;
public static final byte INDICATOR_REPORT = 0x03;

public static final byte ID = (byte)0x87;

private Boolean isOn;

@Override
public byte getId() {
return ID;
}

@Override
public String getName() {
return "COMMAND_CLASS_INDICATOR";
}

public Boolean isOn() {
return isOn;
}

@Override
public void onApplicationCommand(NodeContext context, byte[] ccb, int startIndex) {
if (ccb[startIndex+1] == INDICATOR_REPORT) {
if (ccb[startIndex+2] == 0x00) {
isOn = false;
logger.debug("Received updated isOn (false)");
} else if ((ccb[startIndex+2] >= 0x01 && ccb[startIndex+2] <= 0x63) || ccb[startIndex+2] == (byte)0xFF) {
isOn = true;
logger.debug("Received updated isOn (true)");
} else {
logger.error("Ignoring invalid report value: {}", ByteUtil.createString(ccb[startIndex+2]));
}
} else {
logger.warn("Ignoring unsupported command: {}", ByteUtil.createString(ccb[startIndex+1]));
}
}

@Override
public int queueStartupMessages(NodeContext context, byte nodeId) {
context.sendDataFrame(createGet(nodeId));
return 1;
}

public DataFrame createGet(byte nodeId) {
return createSendDataFrame("INDICATOR_GET", nodeId, new byte[]{IndicatorCommandClass.ID, INDICATOR_GET}, true);
}

public DataFrame createSet(byte nodeId, boolean isOn) {
return createSendDataFrame("INDICATOR_SET", nodeId, new byte[]{IndicatorCommandClass.ID, INDICATOR_SET, isOn ? (byte) 0xFF : (byte) 0x00}, false);
}

@Override
public String toString() {
return "IndicatorCommandClass{" +
"version=" + getVersion() +
", isOn=" + isOn +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public void testCommandClassCreate() {
assertTrue(CommandClassFactory.createCommandClass(BatteryCommandClass.ID) instanceof BatteryCommandClass);
assertTrue(CommandClassFactory.createCommandClass(BinarySensorCommandClass.ID) instanceof BinarySensorCommandClass);
assertTrue(CommandClassFactory.createCommandClass(BinarySwitchCommandClass.ID) instanceof BinarySwitchCommandClass);
assertTrue(CommandClassFactory.createCommandClass(ColorControlCommandClass.ID) instanceof ColorControlCommandClass);
assertTrue(CommandClassFactory.createCommandClass(IndicatorCommandClass.ID) instanceof IndicatorCommandClass);
assertTrue(CommandClassFactory.createCommandClass(ManufacturerSpecificCommandClass.ID) instanceof ManufacturerSpecificCommandClass);
assertTrue(CommandClassFactory.createCommandClass(MeterCommandClass.ID) instanceof MeterCommandClass);
assertTrue(CommandClassFactory.createCommandClass(MultiInstanceCommandClass.ID) instanceof MultiInstanceCommandClass);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*******************************************************************************
* Copyright (c) 2019 Whizzo Software, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.whizzosoftware.wzwave.commandclass;

import com.whizzosoftware.wzwave.frame.DataFrame;
import com.whizzosoftware.wzwave.node.NodeContext;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

public class IndicatorCommandClassTest {
private IndicatorCommandClass icc;

@Before
public void before() {
icc = new IndicatorCommandClass();
}

@Test
public void testDefault() {
assertThat(icc.isOn()).isNull();
}

@Test
public void testStartup() {
NodeContext nodeContext = mock(NodeContext.class);

assertThat(icc.queueStartupMessages(nodeContext, (byte) 0x34)).isEqualTo(1);

ArgumentCaptor<DataFrame> dataFrameCaptor = ArgumentCaptor.forClass(DataFrame.class);
verify(nodeContext).sendDataFrame(dataFrameCaptor.capture());
assertThat(dataFrameCaptor.getValue().getBytes()).containsSequence(commandPayloadOf(0x34, 0x02)); // NodeId, DataLenght, CommandClass, Command
}

@Test
public void testGet() {
DataFrame dataFrame = icc.createGet((byte) 0x45);
assertThat(dataFrame.getBytes()).containsSequence(commandPayloadOf(0x45, 0x02));
}

@Test
public void testSetOff() {
DataFrame dataFrame = icc.createSet((byte) 0x55, false);
assertThat(dataFrame.getBytes()).containsSequence(commandPayloadOf(0x55, 0x01, 0x00));
}

@Test
public void testSetOn() {
DataFrame dataFrame = icc.createSet((byte) 0x28, true);
assertThat(dataFrame.getBytes()).containsSequence(commandPayloadOf(0x28, 0x01, 0xFF));
}

@Test
public void testCallbackOff() {
NodeContext nodeContext = mock(NodeContext.class);

icc.onApplicationCommand(nodeContext, commandPayloadOf(0x34, 0x03, 0x00), 2);

assertThat(icc.isOn()).isFalse();
}

@Test
public void testCallbackOn01() {
NodeContext nodeContext = mock(NodeContext.class);

icc.onApplicationCommand(nodeContext, commandPayloadOf(0x34, 0x03, 0x01), 2);

assertThat(icc.isOn()).isTrue();
}

@Test
public void testCallbackOn63() {
NodeContext nodeContext = mock(NodeContext.class);

icc.onApplicationCommand(nodeContext, commandPayloadOf(0x34, 0x03, 0x63), 2);

assertThat(icc.isOn()).isTrue();
}

@Test
public void testCallbackOnFF() {
NodeContext nodeContext = mock(NodeContext.class);

icc.onApplicationCommand(nodeContext, commandPayloadOf(0x34, 0x03, 0xFF), 2);

assertThat(icc.isOn()).isTrue();
}

@Test
public void testCallbackInvalidValue() {
NodeContext nodeContext = mock(NodeContext.class);

icc.onApplicationCommand(nodeContext, commandPayloadOf(0x34, 0x03, 0x64), 2);

assertThat(icc.isOn()).isNull();
}

@Test
public void testCallbackInvalidCommand() {
NodeContext nodeContext = mock(NodeContext.class);

icc.onApplicationCommand(nodeContext, commandPayloadOf(0x34, 0x02, 0xFF), 2);

assertThat(icc.isOn()).isNull();
}

private byte[] commandPayloadOf(int nodeId, int command, int... values) {
byte[] payload = new byte[4 + values.length];
payload[0] = (byte) nodeId;
payload[1] = (byte) (2 + values.length); // Command length
payload[2] = (byte) 0x87; // Command Class Id
payload[3] = (byte) command;
for (int i = 0; i < values.length; i++)
{
payload[4+i] = (byte) values[i];
}
return payload;
}
}

0 comments on commit b5a3378

Please sign in to comment.