Merge branch 'master' of ssh://home.hottis.de:2922/wolutator/mbusmaster

This commit is contained in:
Wolfgang Hottgenroth 2020-09-09 22:06:18 +02:00
commit 41435e2744
Signed by: wn
GPG Key ID: B586EAFCDF2F65F4
10 changed files with 175 additions and 30 deletions

View File

@ -9,17 +9,17 @@ import org.apache.logging.log4j.Logger;
public abstract class ADataObject implements Serializable {
private static final long serialVersionUID = 1L;
static final String KIND_KEY = "kind";
static final String KIND_KEY = "kind";
final protected Logger logger = LogManager.getRootLogger();
private String name;
private Map<String, Object> values;
private String kind;
private String kind;
public ADataObject(String name, String kind) {
this.name = name;
this.kind = kind;
this.kind = kind;
}
public void setValues(Map<String, Object> values) {
@ -31,11 +31,19 @@ public abstract class ADataObject implements Serializable {
public Map<String, Object> getValues() {
return values;
}
public boolean hasKey(String k) {
return this.values.containsKey(k);
}
public String getName() {
return name;
}
public String getKind() {
return this.kind;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("{\"name\":\"");
@ -54,11 +62,11 @@ public abstract class ADataObject implements Serializable {
sb.append(entry.getKey());
sb.append("\":");
Object value = entry.getValue();
if (! (value instanceof Double)) {
if (! ((value instanceof Double) || (value instanceof Integer))) {
sb.append("\"");
}
sb.append(value);
if (! (value instanceof Double)) {
if (! ((value instanceof Double) || (value instanceof Integer))) {
sb.append("\"");
}
}

View File

@ -16,6 +16,9 @@ public class ConfigProperties extends Properties {
static final String PROPS_VERBOSE = "verbose";
static final String PROPS_MAINCONFIGFILE = "mainConfigFile";
static final String PROPS_ERRORRATIOTHRESHOLD = "errorRatioThreshold";
static final String PROPS_ERRORRATIOCHECKTHRESHOLD = "errorRatioCheckThreshold";
static final String PROPS_LOOPSHUTDOWNDELAY = "loopShutdownDelay";
static final String PROPS_DEVICES = "mbus.device";
static final Logger logger = LogManager.getRootLogger();
@ -80,4 +83,45 @@ public class ConfigProperties extends Properties {
public boolean isVerbose() {
return this.getBooleanProperty("verbose", false) || this.overwriteVerbose;
}
public double getDoubleProperty(String key) throws ConfigPropertiesException {
String v = this.getStringProperty(key);
try {
double o = Double.parseDouble(v);
return o;
} catch (NullPointerException | NumberFormatException e) {
throw new ConfigPropertiesException("Error in getDoubleProperty", e);
}
}
public double getDoubleProperty(String key, double def) {
double returnValue;
try {
returnValue = this.getDoubleProperty(key);
} catch (ConfigPropertiesException e) {
returnValue = def;
}
return returnValue;
}
public int getIntProperty(String key) throws ConfigPropertiesException {
String v = this.getStringProperty(key);
try {
int o = Integer.parseInt(v);
return o;
} catch (NullPointerException | NumberFormatException e) {
throw new ConfigPropertiesException("Error in getIntProperty", e);
}
}
public int getIntProperty(String key, int def) {
int returnValue;
try {
returnValue = this.getIntProperty(key);
} catch (ConfigPropertiesException e) {
returnValue = def;
}
return returnValue;
}
}

View File

@ -6,6 +6,8 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class DummyDequeuer extends Thread {
static final String ERROR_RATIO_KEY = "errorRatio";
static final Logger logger = LogManager.getRootLogger();
public static final String ANSI_RESET = "\u001B[0m";
@ -29,12 +31,15 @@ public class DummyDequeuer extends Thread {
while(true) {
try {
ADataObject o = this.queue.take();
if (((Double)o.getValues().get("errorRatio")) == 0.0) {
if (o.hasKey(ERROR_RATIO_KEY) && ((Double)o.getValues().get(ERROR_RATIO_KEY)) < 0.001) {
System.out.print(ANSI_GREEN);
}
if (((Double)o.getValues().get("errorRatio")) > 0.25) {
if (o.hasKey(ERROR_RATIO_KEY) && ((Double)o.getValues().get(ERROR_RATIO_KEY)) > 0.25) {
System.out.print(ANSI_RED);
}
if ("Statistics".equals(o.getKind())) {
System.out.print(ANSI_CYAN);
}
System.out.print("DummyDequeuer: " + o.toString());
System.out.println(ANSI_RESET);
} catch (InterruptedException e) {

View File

@ -1,6 +1,13 @@
package de.hottis.mbusMaster;
public class FinderOnePhasePowerMeter extends MbusDevice {
public FinderOnePhasePowerMeter(String name, Byte address, Integer queryPeriod) {
this(name, address.byteValue(), queryPeriod.intValue());
}
public FinderOnePhasePowerMeter(String name, byte address, int queryPeriod) {
super(name, address, queryPeriod);
this.dataPoints.add(new DataPoint("energy", 0));

View File

@ -1,6 +1,11 @@
package de.hottis.mbusMaster;
public class FinderThreePhasePowerMeter extends MbusDevice {
public FinderThreePhasePowerMeter(String name, Byte address, Integer queryPeriod) {
this(name, address.byteValue(), queryPeriod.intValue());
}
public FinderThreePhasePowerMeter(String name, byte address, int queryPeriod) {
super(name, address, queryPeriod);
this.dataPoints.add(new DataPoint("energy", 0));

View File

@ -39,6 +39,10 @@ abstract public class MbusDevice {
protected ArrayList<DataPoint> dataPoints;
protected MbusDevice(String name, Byte address, Integer queryPeriod) {
this(name, address.byteValue(), queryPeriod.intValue());
}
protected MbusDevice(String name, byte address, int queryPeriod) {
this.name = name;
this.address = address;

View File

@ -34,6 +34,7 @@ public class MbusMaster {
MbusScheduledQuerier querier = new MbusScheduledQuerier(config, queue);
querier.loadDevices();
querier.start();
DummyDequeuer ddq = new DummyDequeuer(queue);

View File

@ -3,8 +3,12 @@ package de.hottis.mbusMaster;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
import java.util.Enumeration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -12,6 +16,8 @@ import org.apache.logging.log4j.Logger;
public class MbusScheduledQuerier extends Thread {
static final double DEFAULT_ERRORRATIOTHRESHOLD = 0.5;
static final int DEFAULT_ERRORRATIOCHECKTHRESHOLD = 100;
static final int DEFAULT_LOOPSHUTDOWNDELAY = 300; // seconds
static final Logger logger = LogManager.getRootLogger();
@ -28,20 +34,53 @@ public class MbusScheduledQuerier extends Thread {
this.queue = queue;
this.devices = new ArrayList<>();
this.devices.add(new FinderThreePhasePowerMeter("Total Electricity", (byte)80, 0));
this.devices.add(new FinderOnePhasePowerMeter("Dryer", (byte)81, 0));
this.devices.add(new FinderOnePhasePowerMeter("Laundry", (byte)82, 0));
this.devices.add(new FinderOnePhasePowerMeter("Dishwasher", (byte)83, 0));
this.devices.add(new FinderOnePhasePowerMeter("Light", (byte)84, 0));
this.devices.add(new FinderOnePhasePowerMeter("Computer", (byte)85, 0));
this.devices.add(new FinderOnePhasePowerMeter("Freezer", (byte)86, 0));
this.devices.add(new FinderOnePhasePowerMeter("Fridge", (byte)87, 0));
}
public void loadDevices() throws MbusException {
String deviceClassName = null;
try {
@SuppressWarnings("unchecked")
Enumeration<String> propNames = (Enumeration<String>) config.propertyNames();
while (propNames.hasMoreElements()) {
String propName = propNames.nextElement();
if (propName.startsWith(ConfigProperties.PROPS_DEVICES)) {
String[] devicesConfigElements = config.getProperty(propName).split(",");
String name = devicesConfigElements[0];
byte addr = Byte.parseByte(devicesConfigElements[1]);
deviceClassName = devicesConfigElements[2];
int period = Integer.parseInt(devicesConfigElements[3]);
Class<?> klass = Class.forName(deviceClassName);
Constructor<?> constructor = klass.getConstructor(String.class, Byte.class, Integer.class);
MbusDevice device = (MbusDevice) constructor.newInstance(name, addr, period);
this.devices.add(device);
logger.info("Device " + name + " with class " + deviceClassName + ", address " + addr + ", period " + period + " loaded");
}
}
} catch (ClassNotFoundException e) {
String msg = "Device class " + deviceClassName + " not found when loading devices";
logger.error(msg);
throw new MbusException(msg, e);
} catch (NoSuchMethodException e) {
String msg = "Required constructor in device class " + deviceClassName + " not found when loading devices";
logger.error(msg);
throw new MbusException(msg, e);
} catch (InvocationTargetException | IllegalAccessException | InstantiationException e) {
String msg = "Error when instantiating device class " + deviceClassName + " when loading devices";
logger.error(msg);
throw new MbusException(msg, e);
}
}
public void setStopSignal() {
this.stopSignal = true;
}
private int getCurrentTime() {
return (int) (System.currentTimeMillis() / 1000);
}
public void run() {
try {
MbusgwChild mbusgw = new MbusgwChild(config);
@ -51,13 +90,16 @@ public class MbusScheduledQuerier extends Thread {
int errCnt = 0;
int successCnt = 0;
int shutdownCnt = 0;
double maxErrorRatio = 0;
int lastShutdown = this.getCurrentTime();
int timeSinceLastLoopShutdown = 0;
int shutdownTimeSum = 0;
int meantimeBetweenLoopShutdowns = 0;
while (! this.stopSignal) {
cnt++;
double maxErrorRatio = 0;
for (MbusDevice device : this.devices) {
logger.info("Querying " + device.getName() + " meter");
try {
@ -75,12 +117,23 @@ public class MbusScheduledQuerier extends Thread {
errCnt++;
logger.error("Error " + e.toString() + " in Meterbus dialog for device " + device.shortString());
}
this.maxErrorRatio = (this.maxErrorRatio > device.getErrorRatio()) ? this.maxErrorRatio : device.getErrorRatio();
maxErrorRatio = (maxErrorRatio > device.getErrorRatio()) ? maxErrorRatio : device.getErrorRatio();
}
logger.info("CycleCnt: " + cnt + ", SuccessCnt: " + successCnt + ", ErrCnt: " + errCnt +
", MaxErrorRatio: " + maxErrorRatio + ", MeanErrorRatio: " + ((double)errCnt / (double)(errCnt+successCnt)) +
", ShutdownCnt: " + shutdownCnt +
", TimeSinceLastLoopShutdown: " + timeSinceLastLoopShutdown + ", MeantimeBetweenLoopShutdowns: " + meantimeBetweenLoopShutdowns);
this.queue.add(new MbusStatisticsDataObject("MbusgwChild", cnt, errCnt, successCnt, shutdownCnt,
maxErrorRatio, ((double)errCnt / (double)(errCnt+successCnt)),
timeSinceLastLoopShutdown, meantimeBetweenLoopShutdowns));
if ((maxErrorRatio > config.getDoubleProperty(ConfigProperties.PROPS_ERRORRATIOTHRESHOLD, DEFAULT_ERRORRATIOTHRESHOLD)) &&
(cnt % config.getIntProperty(ConfigProperties.PROPS_ERRORRATIOCHECKTHRESHOLD, DEFAULT_ERRORRATIOCHECKTHRESHOLD) == 0)) {
logger.error("maxErrorRatio exceeds threshold and cycleCnt exceeds checkThreshold, request loop shutdown");
if (this.maxErrorRatio > config.getDoubleProperties(ConfigProperties.PROPS_ERRORRATIOTHRESHOLD, DEFAULT_ERRORRATIOTHRESHOLD)) {
// disable loop
shutdownCnt++;
mbusgw.loopShutdown();
// reset counters in devices
for (MbusDevice device : this.devices) {
@ -89,17 +142,26 @@ public class MbusScheduledQuerier extends Thread {
// reset local counters
errCnt = 0;
successCnt = 0;
shutdownCnt++;
// remember time of loop shutdown
// calculate time since last shutdown
// calculate mean time between shutdowns
int currentTime = this.getCurrentTime();
timeSinceLastLoopShutdown = currentTime - lastShutdown;
lastShutdown = currentTime;
shutdownTimeSum += timeSinceLastLoopShutdown;
meantimeBetweenLoopShutdowns = shutdownTimeSum / shutdownCnt;
// delay
int delay = config.getIntProperty(ConfigProperties.PROPS_LOOPSHUTDOWNDELAY, DEFAULT_LOOPSHUTDOWNDELAY);
logger.error("delaying for " + delay + "s");
try {
Thread.sleep(delay * 1000);
} catch (InterruptedException e) {
}
}
logger.info("CycleCnt: " + cnt + ", SuccessCnt: " + successCnt + ", ErrCnt: " + errCnt);
this.queue.add(new MbusStatisticsDataObject("MbusgwChild", errCnt, successCnt, shutdownCnt,
((double)errCnt / (double)(errCnt+successCnt))),
timeSinceLastLoopShutdown, meantimeBetweenLoopShutdowns);
try {
Thread.sleep(5*1000);

View File

@ -6,20 +6,24 @@ public class MbusStatisticsDataObject extends ADataObject {
private static final long serialVersionUID = 1L;
static final String ERROR_CNT_KEY = "error";
static final String SUCCESS_CNT_KEY = "success";
static final String ERROR_RATIO_KEY = "errorRatio";
static final String CYCLE_CNT_KEY = "cycle";
static final String MEAN_ERROR_RATIO_KEY = "meanErrorRatio";
static final String MAX_ERROR_RATIO_KEY = "maxErrorRatio";
static final String TIME_SINCE_LAST_SHUTDOWN_KEY = "timeSinceLastShutdown";
static final String MEANTIME_BETWEEN_SHUTDOWNS_KEY = "meantimeBetweenShutdowns";
static final String SHUTDOWNS_KEY = "shutdowns";
static final String TABLE_NAME = "Statistics";
static final String KIND_NAME = "Statistics";
public MbusStatisticsDataObject(String name, int error, int success, int shutdowns,
double errorRatio, int timeSinceLastShutdown, int meantimeBetweenShutdowns) {
public MbusStatisticsDataObject(String name, int cycle, int error, int success, int shutdowns,
double maxErrorRatio, double meanErrorRatio, int timeSinceLastShutdown, int meantimeBetweenShutdowns) {
super(name, KIND_NAME);
HashMap<String, Object> values = new HashMap<String, Object>();
values.put(CYCLE_CNT_KEY, cycle);
values.put(ERROR_CNT_KEY, error);
values.put(SUCCESS_CNT_KEY, success);
values.put(ERROR_RATIO_KEY, errorRatio);
values.put(MAX_ERROR_RATIO_KEY, maxErrorRatio);
values.put(MEAN_ERROR_RATIO_KEY, meanErrorRatio);
values.put(TIME_SINCE_LAST_SHUTDOWN_KEY, timeSinceLastShutdown);
values.put(MEANTIME_BETWEEN_SHUTDOWNS_KEY, meantimeBetweenShutdowns);
values.put(SHUTDOWNS_KEY, shutdowns);

View File

@ -77,6 +77,11 @@ public class MbusgwChild {
logger.info("Thread joined");
}
public void loopShutdown() throws IOException {
logger.info("Requesting loop shutdown");
this.sendRequest((byte)0, (byte)1);
}
public InputStream getProcessInputStream() {
return this.processInput;
}