[openwebnet] Backport of some fixes from OH 3.1.0 to 2.5.x branch (#9920)

* [openwebnet] Log messages cleanup (2.5.x)

Signed-off-by: Massimo Valla <mvcode00@gmail.com>

* [openwebnet] Fixed normalizeWhere (2.5.x)
* added builder for Bus Where addresses
* added messages to OwnIdTest
* depend on own4j 0.3.3-SNAPSHOT

Signed-off-by: Massimo Valla <mvcode00@gmail.com>

* [openwebnet] fixed up/down automation for old fw (#9651) (2.5.x)
* now using openwebnet4j 0.3.3

Signed-off-by: Massimo Valla <mvcode00@gmail.com>

* [openwebnet] Fixes lowering dimmers from 20 to 10% does not change device level #9317 (2.5.x)
- bump openwebnet4j to 0.3.4

Signed-off-by: Massimo Valla <mvcode00@gmail.com>
This commit is contained in:
M Valla 2021-01-24 16:18:36 +01:00 committed by GitHub
parent 2dd2bb59f4
commit c57d3ee17b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 141 additions and 74 deletions

View File

@ -23,7 +23,7 @@
<dependency>
<groupId>com.github.openwebnet4j</groupId>
<artifactId>openwebnet4j</artifactId>
<version>0.3.2-1</version>
<version>0.3.4</version>
<scope>compile</scope>
</dependency>

View File

@ -41,6 +41,7 @@ import org.openwebnet4j.message.BaseOpenMessage;
import org.openwebnet4j.message.FrameException;
import org.openwebnet4j.message.GatewayMgmt;
import org.openwebnet4j.message.Where;
import org.openwebnet4j.message.WhereLightAutom;
import org.openwebnet4j.message.Who;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -129,6 +130,11 @@ public class OpenWebNetAutomationHandler extends OpenWebNetThingHandler {
positionEstimation = POSITION_UNKNOWN;
}
@Override
protected Where buildBusWhere(String wStr) throws IllegalArgumentException {
return new WhereLightAutom(wStr);
}
@Override
protected void requestChannelState(ChannelUID channel) {
logger.debug("requestChannelState() thingUID={} channel={}", thing.getUID(), channel.getId());
@ -280,8 +286,9 @@ public class OpenWebNetAutomationHandler extends OpenWebNetThingHandler {
@Override
protected void handleMessage(BaseOpenMessage msg) {
logger.debug("handleMessage({}) for thing: {}", msg, thing.getUID());
updateAutomationState((Automation) msg);
// REMINDER: update state, then update thing status in the super method, to avoid delays
// REMINDER: update automation state, and only after update thing status using the super method, to avoid delays
super.handleMessage(msg);
}

View File

@ -111,7 +111,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
updateStatus(ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.UNKNOWN);
logger.debug("Trying to connect gateway...");
logger.debug("Trying to connect gateway {}... ", gw);
try {
gw.connect();
scheduler.schedule(() -> {
@ -233,22 +233,22 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
if (gw != null) {
if (!gw.isDiscovering()) {
if (!gw.isConnected()) {
logger.debug("------$$ Gateway is NOT connected, cannot search for devices");
logger.debug("------$$ Gateway '{}' is NOT connected, cannot search for devices", gw);
return;
}
logger.info("------$$ STARTED active SEARCH for devices on gateway '{}'", this.getThing().getUID());
logger.info("------$$ STARTED active SEARCH for devices on bridge '{}'", thing.getUID());
try {
gw.discoverDevices();
} catch (OWNException e) {
logger.warn("------$$ OWNException while discovering devices on gateway {}: {}",
this.getThing().getUID(), e.getMessage());
logger.warn("------$$ OWNException while discovering devices on bridge '{}': {}", thing.getUID(),
e.getMessage());
}
} else {
logger.debug("------$$ Searching devices on gateway {} already activated", this.getThing().getUID());
return;
}
} else {
logger.debug("------$$ Cannot search devices: no gateway associated to this handler");
logger.warn("------$$ Cannot search devices: no gateway associated to this handler");
}
}
@ -268,7 +268,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
@Override
public void onDiscoveryCompleted() {
logger.info("------$$ FINISHED active SEARCH for devices on gateway '{}'", this.getThing().getUID());
logger.info("------$$ FINISHED active SEARCH for devices on bridge '{}'", thing.getUID());
}
/**
@ -418,10 +418,10 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
return;
}
if (gw instanceof USBGateway) {
logger.info("------------------- CONNECTED to ZigBee USB gateway - USB port: {}",
logger.info("---- CONNECTED to ZigBee USB gateway bridge '{}' (serialPort: {})", thing.getUID(),
((USBGateway) gw).getSerialPortName());
} else {
logger.info("------------------- CONNECTED to BUS gateway '{}' ({}:{})", thing.getUID(),
logger.info("---- CONNECTED to BUS gateway bridge '{}' ({}:{})", thing.getUID(),
((BUSGateway) gw).getHost(), ((BUSGateway) gw).getPort());
// update serial number property (with MAC address)
if (properties.get(PROPERTY_SERIAL_NO) != gw.getMACAddr().toUpperCase()) {
@ -437,7 +437,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
}
if (propertiesChanged) {
updateProperties(properties);
logger.info("properties updated for '{}'", thing.getUID());
logger.info("properties updated for bridge '{}'", thing.getUID());
}
updateStatus(ThingStatus.ONLINE);
}
@ -450,7 +450,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
} else {
errMsg = error.getMessage();
}
logger.info("------------------- ON CONNECTION ERROR: {}", errMsg);
logger.info("---- ON CONNECTION ERROR for gateway {}: {}", gateway, errMsg);
isGatewayConnected = false;
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, errMsg);
tryReconnectGateway();
@ -472,7 +472,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
} else {
errMsg = e.getMessage();
}
logger.info("------------------- DISCONNECTED from gateway. OWNException={}", errMsg);
logger.info("---- DISCONNECTED from gateway {}. OWNException: {}", gateway, errMsg);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
"Disconnected from gateway (onDisconnected - " + errMsg + ")");
tryReconnectGateway();
@ -483,18 +483,18 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
if (gw != null) {
if (!reconnecting) {
reconnecting = true;
logger.info("------------------- Starting RECONNECT cycle to gateway");
logger.info("---- Starting RECONNECT cycle to gateway {}", gw);
try {
gw.reconnect();
} catch (OWNAuthException e) {
logger.info("------------------- AUTH error from gateway. Stopping reconnect");
logger.info("---- AUTH error from gateway. Stopping re-connect");
reconnecting = false;
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
"Authentication error. Check gateway password in Thing Configuration Parameters (" + e
+ ")");
}
} else {
logger.debug("------------------- reconnecting=true, do nothing");
logger.debug("---- reconnecting=true, do nothing");
}
} else {
logger.debug("------------------- cannot start RECONNECT, gateway is null");
@ -504,8 +504,8 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
@Override
public void onReconnected() {
reconnecting = false;
logger.info("------------------- RE-CONNECTED to gateway!");
OpenGateway gw = gateway;
logger.info("---- RE-CONNECTED to bridge {}", thing.getUID());
if (gw != null) {
updateStatus(ThingStatus.ONLINE);
if (gw.getFirmwareVersion() != null) {
@ -568,10 +568,10 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
if (where instanceof WhereZigBee) {
str = ((WhereZigBee) where).valueWithUnit(WhereZigBee.UNIT_ALL); // 76543210X#9 --> 765432100#9
} else {
if (str.indexOf("#4#") == 0) { // no changes needed for local bus: APL#4#bus
if (str.indexOf('#') == 0) { // Thermo zone via central unit: #0 or #Z (Z=[1-99]) --> Z
if (str.indexOf("#4#") == -1) { // skip APL#4#bus case
if (str.indexOf('#') == 0) { // Thermo central unit (#0) or zone via central unit (#Z, Z=[1-99]) --> Z
str = str.substring(1);
} else if (str.indexOf('#') > 0) { // Thermo zone and actuator N: Z#N (Z=[1-99], N=[1-9]) --> Z
} else if (str.indexOf('#') > 0) { // Thermo zone Z and actuator N (Z#N, Z=[1-99], N=[1-9]) --> Z
str = str.substring(0, str.indexOf('#'));
}
}

View File

@ -21,6 +21,8 @@ import org.eclipse.smarthome.core.thing.ThingTypeUID;
import org.eclipse.smarthome.core.types.Command;
import org.openhab.binding.openwebnet.OpenWebNetBindingConstants;
import org.openwebnet4j.message.BaseOpenMessage;
import org.openwebnet4j.message.Where;
import org.openwebnet4j.message.WhereLightAutom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -65,10 +67,15 @@ public class OpenWebNetGenericHandler extends OpenWebNetThingHandler {
return "G";
}
@Override
protected Where buildBusWhere(String wStr) throws IllegalArgumentException {
return new WhereLightAutom(wStr);
}
@Override
protected void handleMessage(BaseOpenMessage msg) {
super.handleMessage(msg);
// do nothing
logger.warn("handleMessage(): Nothing to do!");
}
} // class
}

View File

@ -35,6 +35,7 @@ import org.openwebnet4j.message.FrameException;
import org.openwebnet4j.message.Lighting;
import org.openwebnet4j.message.What;
import org.openwebnet4j.message.Where;
import org.openwebnet4j.message.WhereLightAutom;
import org.openwebnet4j.message.WhereZigBee;
import org.openwebnet4j.message.Who;
import org.slf4j.Logger;
@ -53,15 +54,19 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.LIGHTING_SUPPORTED_THING_TYPES;
private static final int BRIGHTNESS_CHANGE_DELAY_MSEC = 1500; // delay before sending another brightness status
// request
private static final int BRIGHTNESS_STATUS_REQUEST_DELAY_MSEC = 900; // we must wait some time to be sure dimmer has
// reached final level before requesting its
// status
// interval to interpret ON as response to requestStatus
private static final int BRIGHTNESS_STATUS_REQUEST_INTERVAL_MSEC = 250;
// time to wait before sending a statusRequest, to avoid repeated requests and ensure dimmer has reached its final
// level
private static final int BRIGHTNESS_STATUS_REQUEST_DELAY_MSEC = 900;
private static final int UNKNOWN_STATE = 1000;
private long lastBrightnessChangeSentTS = 0; // timestamp when last brightness change was sent to the device
private long lastStatusRequestSentTS = 0; // timestamp when last status request was sent to the device
private int brightness = UNKNOWN_STATE; // current brightness percent value for this device
private int brightnessBeforeOff = UNKNOWN_STATE; // latest brightness before device was set to off
@ -83,6 +88,7 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
Where w = deviceWhere;
if (w != null) {
try {
lastStatusRequestSentTS = System.currentTimeMillis();
Response res = send(Lighting.requestStatus(toWhere(channelId)));
if (res != null && res.isSuccess()) {
// set thing online if not already
@ -214,8 +220,8 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
@Override
protected void handleMessage(BaseOpenMessage msg) {
logger.debug("handleMessage({}) for thing: {}", msg, thing.getUID());
super.handleMessage(msg);
logger.debug("handleMessage() for thing: {}", thing.getUID());
ThingTypeUID thingType = thing.getThingTypeUID();
if (THING_TYPE_ZB_DIMMER.equals(thingType) || THING_TYPE_BUS_DIMMER.equals(thingType)) {
updateBrightness((Lighting) msg);
@ -230,47 +236,54 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
* @param msg the Lighting message received
*/
private synchronized void updateBrightness(Lighting msg) {
long now = System.currentTimeMillis();
logger.debug(" $BRI updateBrightness({}) || bri={} briBeforeOff={}", msg, brightness,
brightnessBeforeOff);
long now = System.currentTimeMillis();
long delta = now - lastBrightnessChangeSentTS;
boolean belowThresh = delta < BRIGHTNESS_CHANGE_DELAY_MSEC;
boolean belowThresh = delta < BRIGHTNESS_STATUS_REQUEST_DELAY_MSEC;
logger.debug(" $BRI delta={}ms {}", delta, (belowThresh ? "< DELAY" : ""));
if (belowThresh) {
// we just sent a command from OH, so we can ignore this message from network
logger.debug(" $BRI a request was sent {} < {} ms --> no action needed", delta,
BRIGHTNESS_CHANGE_DELAY_MSEC);
logger.debug(" $BRI a command was sent {} < {} ms --> no action needed", delta,
BRIGHTNESS_STATUS_REQUEST_DELAY_MSEC);
} else {
if (msg.isOn()) {
logger.debug(" $BRI \"ON\" notification from network, scheduling requestStatus...");
// we must wait BRIGHTNESS_STATUS_REQUEST_DELAY_MSEC to be sure dimmer has reached final level
scheduler.schedule(() -> {
requestStatus(CHANNEL_BRIGHTNESS);
}, BRIGHTNESS_STATUS_REQUEST_DELAY_MSEC, TimeUnit.MILLISECONDS);
} else {
logger.debug(" $BRI update from network");
if (msg.getWhat() != null) {
updateBrightnessState(msg);
} else { // dimension notification
if (msg.getDim() == Lighting.DIM.DIMMER_LEVEL_100) {
int newBrightness;
try {
newBrightness = msg.parseDimmerLevel100();
} catch (FrameException fe) {
logger.warn("updateBrightness() Wrong value for dimmerLevel100 in message: {}", msg);
return;
}
logger.debug(" $BRI DIMMER_LEVEL_100 newBrightness={}", newBrightness);
updateState(CHANNEL_BRIGHTNESS, new PercentType(newBrightness));
if (newBrightness == 0) {
brightnessBeforeOff = brightness;
}
brightness = newBrightness;
} else {
logger.warn("updateBrightness() Cannot handle message {} for thing {}", msg,
getThing().getUID());
// if we have not just sent a requestStatus, on ON event we send requestStatus to know current level
long deltaStatusReq = now - lastStatusRequestSentTS;
if (deltaStatusReq > BRIGHTNESS_STATUS_REQUEST_INTERVAL_MSEC) {
logger.debug(" $BRI 'ON' is new notification from network, scheduling requestStatus...");
// we must wait BRIGHTNESS_STATUS_REQUEST_DELAY_MSEC to be sure dimmer has reached its final level
scheduler.schedule(() -> {
requestStatus(CHANNEL_BRIGHTNESS);
}, BRIGHTNESS_STATUS_REQUEST_DELAY_MSEC, TimeUnit.MILLISECONDS);
return;
} else {
// otherwise we interpret this ON event as the requestStatus response event with level=1
// so we proceed to call updateBrightnessState()
logger.debug(" $BRI 'ON' is the requestStatus response level");
}
}
logger.debug(" $BRI update from network");
if (msg.getWhat() != null) {
updateBrightnessState(msg);
} else { // dimension notification
if (msg.getDim() == Lighting.DIM.DIMMER_LEVEL_100) {
int newBrightness;
try {
newBrightness = msg.parseDimmerLevel100();
} catch (FrameException fe) {
logger.warn("updateBrightness() Wrong value for dimmerLevel100 in message: {}", msg);
return;
}
logger.debug(" $BRI DIMMER_LEVEL_100 newBrightness={}", newBrightness);
updateState(CHANNEL_BRIGHTNESS, new PercentType(newBrightness));
if (newBrightness == 0) {
brightnessBeforeOff = brightness;
}
brightness = newBrightness;
} else {
logger.warn("updateBrightness() Cannot handle message {} for thing {}", msg, getThing().getUID());
return;
}
}
}
@ -284,8 +297,12 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
* @param msg the Lighting message received
*/
private void updateBrightnessState(Lighting msg) {
if (msg.getWhat() != null) {
int newBrightnessWhat = msg.getWhat().value();
What w = msg.getWhat();
if (w != null) {
if (Lighting.WHAT.ON.equals(w)) {
w = Lighting.WHAT.DIMMER_LEVEL_2; // levels start at 2
}
int newBrightnessWhat = w.value();
int brightnessWhat = UNKNOWN_STATE;
if (brightness != UNKNOWN_STATE) {
brightnessWhat = Lighting.percentToWhat(brightness).value();
@ -344,6 +361,11 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
}
}
@Override
protected Where buildBusWhere(String wStr) throws IllegalArgumentException {
return new WhereLightAutom(wStr);
}
/**
* Returns a WHERE address string based on channelId string
*

View File

@ -34,7 +34,6 @@ import org.openwebnet4j.communication.Response;
import org.openwebnet4j.message.BaseOpenMessage;
import org.openwebnet4j.message.OpenMessage;
import org.openwebnet4j.message.Where;
import org.openwebnet4j.message.WhereLightAutom;
import org.openwebnet4j.message.WhereZigBee;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -77,7 +76,7 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
Where w;
try {
if (brH.isBusGateway()) {
w = new WhereLightAutom(deviceWhereStr);
w = buildBusWhere(deviceWhereStr);
} else {
w = new WhereZigBee(deviceWhereStr);
}
@ -192,6 +191,14 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
*/
protected abstract void requestChannelState(ChannelUID channel);
/**
* Abstract builder for device Where address, to be implemented by each subclass to choose the right Where subclass
* (the method is used only if the Thing is associated to a BUS gateway).
*
* @param wStr the WHERE string
*/
protected abstract Where buildBusWhere(String wStr) throws IllegalArgumentException;
@Override
public void dispose() {
OpenWebNetBridgeHandler bh = bridgeHandler;

View File

@ -16,13 +16,17 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.thing.Bridge;
import org.junit.Test;
import org.openwebnet4j.message.Lighting;
import org.openwebnet4j.message.BaseOpenMessage;
import org.openwebnet4j.message.FrameException;
import org.openwebnet4j.message.Where;
import org.openwebnet4j.message.WhereLightAutom;
import org.openwebnet4j.message.WhereZigBee;
import org.openwebnet4j.message.Who;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Test class for {@link OpenWebNetBridgeHandler#ownID} and ThingID calculation using {@link OpenWebNetBridgeHandler}
@ -33,6 +37,8 @@ import org.openwebnet4j.message.Who;
@NonNullByDefault
public class OwnIdTest {
private final Logger logger = LoggerFactory.getLogger(OwnIdTest.class);
// @formatter:off
/**
*
@ -57,22 +63,37 @@ public class OwnIdTest {
// @formatter:on
public enum TEST {
zb_switch(new WhereZigBee("789309801#9"), Who.fromValue(1), "789309800h9", "1.789309800h9", "789309800h9"),
zb_switch_2u_1(new WhereZigBee("789301201#9"), Who.fromValue(1), "789301200h9", "1.789301200h9", "789301200h9"),
zb_switch_2u_2(new WhereZigBee("789301202#9"), Who.fromValue(1), "789301200h9", "1.789301200h9", "789301200h9"),
bus_switch(new WhereLightAutom("51"), Who.fromValue(1), "51", "1.51", "51"),
bus_localbus(new WhereLightAutom("25#4#01"), Who.fromValue(1), "25h4h01", "1.25h4h01", "25h4h01");
// bus_thermo("#1", "4", "1", "4.1", "1"),
// @formatter:off
zb_switch(new WhereZigBee("789309801#9"), Who.fromValue(1), "*1*1*789309801#9##", "789309800h9", "1.789309800h9", "789309800h9"),
zb_switch_2u_1(new WhereZigBee("789301201#9"), Who.fromValue(1), "*1*1*789301201#9##", "789301200h9", "1.789301200h9", "789301200h9"),
zb_switch_2u_2(new WhereZigBee("789301202#9"), Who.fromValue(1), "*1*1*789301202#9##", "789301200h9", "1.789301200h9", "789301200h9"),
bus_switch(new WhereLightAutom("51"), Who.fromValue(1), "*1*1*51##", "51", "1.51", "51"),
bus_localbus(new WhereLightAutom("25#4#01"), Who.fromValue(1), "*1*1*25#4#01##", "25h4h01", "1.25h4h01", "25h4h01");
//bus_thermo_zone(new WhereThermo("1"), Who.fromValue(4),"*#4*1*0*0020##" , "1", "4.1", "1"),
//bus_thermo_zone_act(new WhereThermo("2#1"), Who.fromValue(4),"*#4*2#1*20*0##" ,"2", "4.2", "2"),
//bus_thermo_via_cu(new WhereThermo("#1"), Who.fromValue(4),"*#4*#1*0*0020##" ,"1", "4.1", "1"),
// bus_tempSensor("500", "4", "500", "4.500", "500"),
// bus_energy("51", "18", "51", "18.51", "51");
// @formatter:on
private final Logger logger = LoggerFactory.getLogger(TEST.class);
public final Where where;
public final Who who;
public final @Nullable BaseOpenMessage msg;
public final String norm, ownId, thingId;
private TEST(Where where, Who who, String norm, String ownId, String thingId) {
private TEST(Where where, Who who, String msg, String norm, String ownId, String thingId) {
this.where = where;
this.who = who;
BaseOpenMessage bmsg = null;
try {
bmsg = (BaseOpenMessage) BaseOpenMessage.parse(msg);
} catch (FrameException e) {
logger.warn("something is wrong in the test table. ownIdFromMessage test will be skipped");
}
this.msg = bmsg;
this.norm = norm;
this.ownId = ownId;
this.thingId = thingId;
@ -83,13 +104,16 @@ public class OwnIdTest {
public void testOwnId() {
Bridge mockBridge = mock(Bridge.class);
OpenWebNetBridgeHandler brH = new OpenWebNetBridgeHandler(mockBridge);
BaseOpenMessage bmsg;
for (int i = 0; i < TEST.values().length; i++) {
TEST test = TEST.values()[i];
// System.out.println("testing where=" + test.where);
logger.info("testing where={}", test.where);
assertEquals(test.norm, brH.normalizeWhere(test.where));
assertEquals(test.ownId, brH.ownIdFromWhoWhere(test.who, test.where));
assertEquals(test.ownId, brH.ownIdFromMessage(Lighting.requestTurnOn(test.where.value())));
bmsg = test.msg;
if (bmsg != null) {
assertEquals(test.ownId, brH.ownIdFromMessage(bmsg));
}
assertEquals(test.thingId, brH.thingIdFromWhere(test.where));
}
}