/* * Dog - Device Driver * * Copyright (c) 2012-2014 Luigi De Russis * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package it.polito.elite.dog.drivers.knx.singlephaseelectricitymeter; import it.polito.elite.dog.core.library.util.LogHelper; import it.polito.elite.dog.core.library.model.ControllableDevice; import it.polito.elite.dog.core.library.model.DeviceStatus; import it.polito.elite.dog.core.library.model.devicecategory.SinglePhaseElectricityMeter; import it.polito.elite.dog.core.library.model.notification.FrequencyMeasurementNotification; import it.polito.elite.dog.core.library.model.notification.PowerFactorMeasurementNotification; import it.polito.elite.dog.core.library.model.notification.SinglePhaseActiveEnergyMeasurementNotification; import it.polito.elite.dog.core.library.model.notification.SinglePhaseActivePowerMeasurementNotification; import it.polito.elite.dog.core.library.model.notification.SinglePhaseApparentPowerMeasurementNotification; import it.polito.elite.dog.core.library.model.notification.SinglePhaseCurrentMeasurementNotification; import it.polito.elite.dog.core.library.model.notification.SinglePhaseReactiveEnergyMeasurementNotification; import it.polito.elite.dog.core.library.model.notification.SinglePhaseReactivePowerMeasurementNotification; import it.polito.elite.dog.core.library.model.notification.SinglePhaseVoltageMeasurementNotification; import it.polito.elite.dog.core.library.model.state.FrequencyMeasurementState; import it.polito.elite.dog.core.library.model.state.PowerFactorMeasurementState; import it.polito.elite.dog.core.library.model.state.SinglePhaseActiveEnergyState; import it.polito.elite.dog.core.library.model.state.SinglePhaseActivePowerMeasurementState; import it.polito.elite.dog.core.library.model.state.SinglePhaseApparentPowerMeasurementState; import it.polito.elite.dog.core.library.model.state.SinglePhaseCurrentState; import it.polito.elite.dog.core.library.model.state.SinglePhaseReactiveEnergyState; import it.polito.elite.dog.core.library.model.state.SinglePhaseReactivePowerMeasurementState; import it.polito.elite.dog.core.library.model.state.SinglePhaseVoltageState; import it.polito.elite.dog.core.library.model.state.VoltageMeasurementState; import it.polito.elite.dog.core.library.model.statevalue.ActiveEnergyStateValue; import it.polito.elite.dog.core.library.model.statevalue.ActivePowerStateValue; import it.polito.elite.dog.core.library.model.statevalue.ApparentPowerStateValue; import it.polito.elite.dog.core.library.model.statevalue.CurrentStateValue; import it.polito.elite.dog.core.library.model.statevalue.FrequencyStateValue; import it.polito.elite.dog.core.library.model.statevalue.PowerFactorStateValue; import it.polito.elite.dog.core.library.model.statevalue.ReactiveEnergyStateValue; import it.polito.elite.dog.core.library.model.statevalue.ReactivePowerStateValue; import it.polito.elite.dog.core.library.model.statevalue.VoltageStateValue; import it.polito.elite.dog.drivers.knx.network.KnxIPDriverInstance; import it.polito.elite.dog.drivers.knx.network.info.KnxIPDeviceInfo; import it.polito.elite.dog.drivers.knx.network.interfaces.KnxIPNetwork; import java.net.InetAddress; import java.util.HashMap; import java.util.Map; import java.util.Set; import javax.measure.DecimalMeasure; import javax.measure.Measure; import javax.measure.quantity.Power; import javax.measure.unit.NonSI; import javax.measure.unit.SI; import javax.measure.unit.Unit; import org.osgi.framework.BundleContext; import org.osgi.service.log.LogService; import tuwien.auto.calimero.dptxlator.DPT; import tuwien.auto.calimero.dptxlator.DPTXlator4ByteFloat; import tuwien.auto.calimero.dptxlator.DPTXlator4ByteInteger; /** * @author <a href="mailto:luigi.derussis@polito.it">Luigi De Russis</a> * @see <a href="http://elite.polito.it">http://elite.polito.it</a> * */ public class KnxIPSinglePhaseElectricityMeterDriverInstance extends KnxIPDriverInstance implements SinglePhaseElectricityMeter { // the device state private DeviceStatus innerState; // the notification name to DPT map private Map<String, DPT> notification2DPT; // the driver logger LogHelper logger; // the log identifier, unique for the class public static String logId = "[KnxIPSinglePhaseElectricityMeterDriverInstance]: "; /** * The class constructor, initializes all the needed data structures. * * @param network * The network driver to use for communicating with the KNX * network. * @param device * The device to manage. * @param gwAddress */ public KnxIPSinglePhaseElectricityMeterDriverInstance(KnxIPNetwork network, ControllableDevice device, String gatewayAddress, BundleContext context) { // call the super constructor... super(network, device, gatewayAddress); // create a logger this.logger = new LogHelper(context); } /** * Initializes the map for getting the right DPT given a notification name */ private void initializeNotification2DPT() { this.notification2DPT.put(FrequencyMeasurementNotification.class.getSimpleName(), DPTXlator4ByteFloat.DPT_FREQUENCY); this.notification2DPT.put(SinglePhaseReactivePowerMeasurementNotification.class.getSimpleName(), DPTXlator4ByteFloat.DPT_REACTIVE_POWER); this.notification2DPT.put(SinglePhaseReactiveEnergyMeasurementNotification.class.getSimpleName(), DPTXlator4ByteInteger.DPT_REACTIVE_ENERGY); this.notification2DPT.put(SinglePhaseActiveEnergyMeasurementNotification.class.getSimpleName(), DPTXlator4ByteInteger.DPT_ACTIVE_ENERGY); this.notification2DPT.put(SinglePhaseVoltageMeasurementNotification.class.getSimpleName(), DPTXlator4ByteFloat.DPT_ELECTRIC_POTENTIAL_DIFFERENCE); this.notification2DPT.put(SinglePhaseApparentPowerMeasurementNotification.class.getSimpleName(), DPTXlator4ByteFloat.DPT_APPARENT_POWER); this.notification2DPT.put(PowerFactorMeasurementNotification.class.getSimpleName(), DPTXlator4ByteFloat.DPT_POWER_FACTOR); this.notification2DPT.put(SinglePhaseActivePowerMeasurementNotification.class.getSimpleName(), DPTXlator4ByteFloat.DPT_POWER); this.notification2DPT.put(SinglePhaseActivePowerMeasurementNotification.class.getSimpleName(), DPTXlator4ByteFloat.DPT_POWER); this.notification2DPT.put(SinglePhaseCurrentMeasurementNotification.class.getSimpleName(), DPTXlator4ByteFloat.DPT_ELECTRIC_CURRENT); } /** * Initializes the device states and performs an initial read to update * them, if available */ // TODO Check if it is correct! private void initializeStates() { // create the var and va units Unit<Power> VAR = SI.WATT.alternate("var"); Unit<Power> VA = SI.WATT.alternate("VA"); // create all the states... // active power state ActivePowerStateValue initialActivePowerValue = new ActivePowerStateValue(); initialActivePowerValue.setValue(DecimalMeasure.valueOf(0, SI.WATT)); this.innerState.setState(SinglePhaseActivePowerMeasurementState.class.getSimpleName(), new SinglePhaseActivePowerMeasurementState(initialActivePowerValue)); // frequency state FrequencyStateValue initialFrequenceValue = new FrequencyStateValue(); initialFrequenceValue.setValue(DecimalMeasure.valueOf(0, SI.HERTZ)); this.innerState.setState(FrequencyMeasurementState.class.getSimpleName(), new FrequencyMeasurementState( initialFrequenceValue)); // active energy state ActiveEnergyStateValue initialActiveEnergyValue = new ActiveEnergyStateValue(); initialActiveEnergyValue.setValue(DecimalMeasure.valueOf(0, SI.WATT.times(NonSI.HOUR))); this.innerState.setState(SinglePhaseActiveEnergyState.class.getSimpleName(), new SinglePhaseActiveEnergyState( initialActiveEnergyValue)); // current state CurrentStateValue initialCurrentValue = new CurrentStateValue(); initialCurrentValue.setValue(DecimalMeasure.valueOf(0, SI.AMPERE)); this.innerState.setState(SinglePhaseCurrentState.class.getSimpleName(), new SinglePhaseCurrentState( initialCurrentValue)); // reactive power state ReactivePowerStateValue initialReactivePowerValue = new ReactivePowerStateValue(); initialReactivePowerValue.setValue(DecimalMeasure.valueOf(0, VAR)); this.innerState.setState(SinglePhaseReactivePowerMeasurementState.class.getSimpleName(), new SinglePhaseReactivePowerMeasurementState(initialReactivePowerValue)); // power factor state PowerFactorStateValue initialPowerFactorValue = new PowerFactorStateValue(); initialPowerFactorValue.setValue(DecimalMeasure.valueOf("0 " + Unit.ONE)); this.innerState.setState(PowerFactorMeasurementState.class.getCanonicalName(), new PowerFactorMeasurementState( initialPowerFactorValue)); // apparent power state ApparentPowerStateValue initialApparentPowerValue = new ApparentPowerStateValue(); initialApparentPowerValue.setValue(DecimalMeasure.valueOf("0 " + VA)); this.innerState.setState(SinglePhaseApparentPowerMeasurementState.class.getSimpleName(), new SinglePhaseApparentPowerMeasurementState(initialApparentPowerValue)); // reactive energy state ReactiveEnergyStateValue initialReactiveEnergyValue = new ReactiveEnergyStateValue(); initialReactiveEnergyValue.setValue(DecimalMeasure.valueOf(0, VAR.times(NonSI.HOUR))); this.innerState.setState(SinglePhaseReactiveEnergyState.class.getSimpleName(), new SinglePhaseReactiveEnergyState(initialReactiveEnergyValue)); // voltage state VoltageStateValue initialVoltageValue = new VoltageStateValue(); initialVoltageValue.setValue(DecimalMeasure.valueOf("0 " + SI.VOLT)); this.innerState.setState(SinglePhaseVoltageState.class.getSimpleName(), new SinglePhaseVoltageState( initialVoltageValue)); // iterate over all the notifications for (String groupAddress : this.groupAddress2NotificationMap.keySet()) { // read states (asynchronously) try { KnxIPDeviceInfo devInfo = new KnxIPDeviceInfo(this.device.getDeviceId(), groupAddress); devInfo.setGatewayIPAddress(InetAddress.getByName(this.gwAddress)); this.network.read(devInfo); } catch (Exception e) { // TODO handle exception here } } } @Override public Measure<?, ?> getReactiveEnergyValue() { // TODO Check if it works... and then extend to multiple state values return (Measure<?, ?>) this.innerState.getState(SinglePhaseReactiveEnergyState.class.getSimpleName()) .getCurrentStateValue()[0].getValue(); } @Override public Measure<?, ?> getReactivePower() { // TODO Check if it works... and then extend to multiple state values return (Measure<?, ?>) this.innerState.getState(SinglePhaseReactivePowerMeasurementState.class.getSimpleName()) .getCurrentStateValue()[0].getValue(); } @Override public Measure<?, ?> getFrequency() { // TODO Check if it works... and then extend to multiple state values return (Measure<?, ?>) this.innerState.getState(FrequencyMeasurementState.class.getSimpleName()) .getCurrentStateValue()[0].getValue(); } @Override public Measure<?, ?> getPowerFactor() { // TODO Check if it works... and then extend to multiple state values return (Measure<?, ?>) this.innerState.getState(PowerFactorMeasurementState.class.getSimpleName()) .getCurrentStateValue()[0].getValue(); } @Override public Measure<?, ?> getActiveEnergyValue() { // TODO Check if it works... and then extend to multiple state values return (Measure<?, ?>) this.innerState.getState(SinglePhaseActiveEnergyState.class.getSimpleName()) .getCurrentStateValue()[0].getValue(); } @Override public Measure<?, ?> getPhaseNeutralVoltageValue() { // TODO Check if it works... and then extend to multiple state values return (Measure<?, ?>) this.innerState.getState(VoltageMeasurementState.class.getSimpleName()) .getCurrentStateValue()[0].getValue(); } @Override public Measure<?, ?> getElectricCurrentValue() { // TODO Check if it works... and then extend to multiple state values return (Measure<?, ?>) this.innerState.getState(SinglePhaseCurrentState.class.getSimpleName()) .getCurrentStateValue()[0].getValue(); } @Override public Measure<?, ?> getApparentPower() { // TODO Check if it works... and then extend to multiple state values return (Measure<?, ?>) this.innerState.getState(SinglePhaseApparentPowerMeasurementState.class.getSimpleName()) .getCurrentStateValue()[0].getValue(); } @Override public Measure<?, ?> getActivePower() { // TODO Check if it works... and then extend to multiple state values return (Measure<?, ?>) this.innerState.getState(SinglePhaseActivePowerMeasurementState.class.getSimpleName()) .getCurrentStateValue()[0].getValue(); } @Override public DeviceStatus getState() { return this.innerState; } @Override public void notifyNewFrequencyValue(Measure<?, ?> frequency) { // update the state FrequencyStateValue newFrequency = new FrequencyStateValue(); newFrequency.setValue(frequency); this.innerState.setState(FrequencyMeasurementState.class.getSimpleName(), new FrequencyMeasurementState( newFrequency)); // notify the new measure ((SinglePhaseElectricityMeter) this.device).notifyNewFrequencyValue(frequency); } @Override public void notifyNewActivePowerValue(Measure<?, ?> powerValue) { // update the state ActivePowerStateValue newActivePowerValue = new ActivePowerStateValue(); newActivePowerValue.setValue(powerValue); this.innerState.setState(SinglePhaseActivePowerMeasurementState.class.getSimpleName(), new SinglePhaseActivePowerMeasurementState(newActivePowerValue)); // notify the new measure ((SinglePhaseElectricityMeter) this.device).notifyNewActivePowerValue(powerValue); } @Override public void notifyNewReactivePowerValue(Measure<?, ?> powerValue) { // update the state ReactivePowerStateValue newReactivePowerValue = new ReactivePowerStateValue(); newReactivePowerValue.setValue(powerValue); this.innerState.setState(SinglePhaseReactivePowerMeasurementState.class.getSimpleName(), new SinglePhaseReactivePowerMeasurementState(newReactivePowerValue)); // notify the new measure ((SinglePhaseElectricityMeter) this.device).notifyNewReactivePowerValue(powerValue); } @Override public void notifyNewApparentPowerValue(Measure<?, ?> powerValue) { // update the state ApparentPowerStateValue newApparentPowerValue = new ApparentPowerStateValue(); newApparentPowerValue.setValue(powerValue); this.innerState.setState(SinglePhaseApparentPowerMeasurementState.class.getSimpleName(), new SinglePhaseApparentPowerMeasurementState(newApparentPowerValue)); // notify the new measure ((SinglePhaseElectricityMeter) this.device).notifyNewApparentPowerValue(powerValue); } @Override public void notifyNewReactiveEnergyValue(Measure<?, ?> value) { // update the state ReactiveEnergyStateValue newReactiveEnergyValue = new ReactiveEnergyStateValue(); newReactiveEnergyValue.setValue(value); this.innerState.setState(SinglePhaseReactiveEnergyState.class.getSimpleName(), new SinglePhaseReactiveEnergyState(newReactiveEnergyValue)); // notify the new measure ((SinglePhaseElectricityMeter) this.device).notifyNewReactiveEnergyValue(value); } @Override public void notifyNewActiveEnergyValue(Measure<?, ?> value) { // update the state ActiveEnergyStateValue newActiveEnergyValue = new ActiveEnergyStateValue(); newActiveEnergyValue.setValue(value); this.innerState.setState(SinglePhaseActiveEnergyState.class.getSimpleName(), new SinglePhaseActiveEnergyState( newActiveEnergyValue)); // notify the new measure ((SinglePhaseElectricityMeter) this.device).notifyNewActiveEnergyValue(value); } @Override public void notifyNewPowerFactorValue(Measure<?, ?> powerFactor) { // update the state PowerFactorStateValue newPowerFactorValue = new PowerFactorStateValue(); newPowerFactorValue.setValue(powerFactor); this.innerState.setState(PowerFactorMeasurementState.class.getSimpleName(), new PowerFactorMeasurementState( newPowerFactorValue)); // notify the new measure ((SinglePhaseElectricityMeter) this.device).notifyNewPowerFactorValue(powerFactor); } @Override public void notifyNewPhaseNeutralVoltageValue(Measure<?, ?> lnVoltage) { // update the state VoltageStateValue newVoltageValue = new VoltageStateValue(); newVoltageValue.setValue(lnVoltage); this.innerState.setState(VoltageMeasurementState.class.getSimpleName(), new VoltageMeasurementState( newVoltageValue)); // notify the new measure ((SinglePhaseElectricityMeter) this.device).notifyNewPhaseNeutralVoltageValue(lnVoltage); } @Override public void notifyNewCurrentValue(Measure<?, ?> value) { // update the state CurrentStateValue newCurrentValue = new CurrentStateValue(); newCurrentValue.setValue(value); this.innerState.setState(SinglePhaseCurrentState.class.getSimpleName(), new SinglePhaseCurrentState( newCurrentValue)); // notify the new measure ((SinglePhaseElectricityMeter) this.device).notifyNewCurrentValue(value); } @Override public void newMessageFromHouse(String source, String destination, String value) { // re-map back to notifications and state updates... Set<KnxIPDeviceInfo> allCompatibleNotifications = this.groupAddress2NotificationMap.get(destination); // on the basis of the notification call the right notify method for (KnxIPDeviceInfo cInfo : allCompatibleNotifications) { // get the notification name... String notificationName = cInfo.getName(); // call the right notify method depending on the notification name // TODO find a better solution because this is HORRIBLE!!!! if (notificationName.equals(FrequencyMeasurementNotification.class.getSimpleName())) { this.notifyNewFrequencyValue(DecimalMeasure.valueOf(value)); } else if (notificationName.equals(SinglePhaseReactivePowerMeasurementNotification.class.getSimpleName())) { this.notifyNewReactivePowerValue(DecimalMeasure.valueOf(value)); } else if (notificationName.equals(SinglePhaseVoltageMeasurementNotification.class.getSimpleName())) { this.notifyNewPhaseNeutralVoltageValue(DecimalMeasure.valueOf(value)); } else if (notificationName.equals(SinglePhaseApparentPowerMeasurementNotification.class.getSimpleName())) { this.notifyNewApparentPowerValue(DecimalMeasure.valueOf(value)); } else if (notificationName.equals(SinglePhaseActivePowerMeasurementNotification.class.getSimpleName())) { this.notifyNewActivePowerValue(DecimalMeasure.valueOf(value)); } else if (notificationName.equals(SinglePhaseCurrentMeasurementNotification.class.getSimpleName())) { this.notifyNewCurrentValue(DecimalMeasure.valueOf(value)); } else if (notificationName.equals(SinglePhaseReactiveEnergyMeasurementNotification.class.getSimpleName())) { this.notifyNewReactiveEnergyValue(DecimalMeasure.valueOf(value)); } else if (notificationName.equals(SinglePhaseActiveEnergyMeasurementNotification.class.getSimpleName())) { this.notifyNewActiveEnergyValue(DecimalMeasure.valueOf(value)); } else if (notificationName.equals(PowerFactorMeasurementNotification.class.getSimpleName())) { this.notifyNewPowerFactorValue(DecimalMeasure.valueOf(value)); } } // notify the monitor admin... this.updateStatus(); } @Override protected void addToNetworkDriver(KnxIPDeviceInfo deviceInfo) { // get the notification set associated to the given group address Set<KnxIPDeviceInfo> notificationsSet = this.groupAddress2NotificationMap.get(deviceInfo.getGroupAddress()); // prepare the DPT variable DPT cDpt = null; // if the set of device notifications is not null if (notificationsSet != null) { // try to detect the right DPT... for (KnxIPDeviceInfo cInfo : notificationsSet) { if (cDpt == null) { cDpt = this.notification2DPT.get(cInfo.getName()); } else { if (!this.notification2DPT.get(cInfo.getName()).getUnit().equals(cDpt.getUnit())) { // do nothing and log the error... this.logger.log(LogService.LOG_ERROR, KnxIPSinglePhaseElectricityMeterDriverInstance.logId + "Found Incompatible DPTs for the same group address " + deviceInfo.getGroupAddress() + " ignoring the corresponding notification"); cDpt = null; break; } } } // add the dpt if not null if (cDpt != null) { try { KnxIPDeviceInfo devInfo = new KnxIPDeviceInfo(this.device.getDeviceId(), deviceInfo.getGroupAddress()); devInfo.setGatewayIPAddress(InetAddress.getByName(this.gwAddress)); this.network.addDriver(devInfo, 14, cDpt, this); // TODO Is // 14 // correct? } catch (Exception e) { // TODO handle exception here } } } } @Override protected void specificConfiguration() { // prepare the device state map this.innerState = new DeviceStatus(device.getDeviceId()); // TODO: get the initial state of the device....(states can be updated // by reading notification group addresses) this.initializeStates(); // initialize the notification to DPXlator conversion map this.notification2DPT = new HashMap<String, DPT>(); this.initializeNotification2DPT(); } @Override public void updateStatus() { ((SinglePhaseElectricityMeter) this.device).updateStatus(); } }