Java tutorial
/** * This file is part of JEMMA - http://jemma.energy-home.org * (C) Copyright 2013 Telecom Italia (http://www.telecomitalia.it) * * JEMMA is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License (LGPL) version 3 * or later as published by the Free Software Foundation, which accompanies * this distribution and is available at http://www.gnu.org/licenses/lgpl.html * * JEMMA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License (LGPL) for more details. * */ package org.energy_home.jemma.ah.ebrain; //import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.energy_home.jemma.ah.ebrain.IOverloadStatusListener.OverloadStatus; import org.energy_home.jemma.ah.ebrain.algo.DailyTariff; import org.energy_home.jemma.ah.hap.client.M2MHapException; import org.energy_home.jemma.m2m.ContentInstance; import org.energy_home.jemma.m2m.ah.ApplianceLog; import org.energy_home.jemma.m2m.ah.MinMaxPowerInfo; import org.energy_home.jemma.shal.DeviceInfo; import org.energy_home.jemma.shal.DeviceListener; import org.energy_home.jemma.shal.DeviceService; import org.energy_home.jemma.shal.DeviceConfiguration.DeviceCategory; import org.energy_home.jemma.shal.DeviceDescriptor.DeviceType; public class MeteringCore implements IMeteringListener, DeviceListener { private static final Log log = LogFactory.getLog(MeteringCore.class.getSimpleName()); private static final IOverloadStatusListener dummyOverloadListener = new IOverloadStatusListener() { public void notifyOverloadStatusUpdate(OverloadStatus status) { // TODO Auto-generated method stub } }; private static final ICloudServiceProxy dummyCloudProxy = new ICloudServiceProxy() { public void storeEvent(String applianceId, long time, int eventType) throws Exception { } public void storeApplianceStatistics(String applianceId, long time, ApplianceLog applianceLog) throws Exception { } public ContentInstance retrieveDeliveredEnergySummation(String applianceId) { return null; } public void storeReceivedEnergy(String applianceId, long time, double totalEnergy) throws Exception { // TODO Auto-generated method stub } public void storeDeliveredEnergy(String applianceId, long time, double totalEnergy) throws Exception { // TODO Auto-generated method stub } public void storeDeliveredEnergyCostPowerInfo(String applianceId, EnergyCostInfo eci, MinMaxPowerInfo powerInfo) throws Exception { // TODO Auto-generated method stub } public void storeReceivedEnergyCostPowerInfo(String applianceId, EnergyCostInfo eci, MinMaxPowerInfo powerInfo) throws Exception { // TODO Auto-generated method stub } public List<Float> retrieveHourlyProducedEnergyForecast(String applianceId) { // TODO Auto-generated method stub return null; } }; private static final long SMART_INFO_POLLING_MIN_INTERVAL_MILLISEC = 10 * 1000;//30 * 1000 private static final long SMART_INFO_POLLING_NORMAL_INTERVAL_MILLISEC = 10 * 1000;// 60 * 3 *1000; public static final long SMART_INFO_SUMMATION_MIN_INTERVAL = 2; public static final long SMART_INFO_SUMMATION_MAX_INTERVAL = 15; //120; MaximumReportingInterval public static final double SMART_INFO_SUMMATION_DELTA_VALUE = 5; //1 public static final long DEFAULT_SUMMATION_MIN_INTERVAL = 120; public static final long DEFAULT_SUMMATION_MAX_INTERVAL = 120; public static final double DEFAULT_SUMMATION_DELTA_VALUE = 4500; public static final long DEFAULT_ONOFF_MIN_INTERVAL = 2; public static final long DEFAULT_ONOFF_MAX_INTERVAL = 120; public static final long SMART_INFO_INST_DEMAND_MIN_INTERVAL = 2; public static final long SMART_INFO_INST_DEMAND_MAX_INTERVAL = 120; public static final float SMART_INFO_INST_DEMAND_DELTA_VALUE = 5; public static final long DEFAULT_INST_DEMAND_MIN_INTERVAL = 2; public static final long DEFAULT_INST_DEMAND_MAX_INTERVAL = 120; public static final float DEFAULT_INST_DEMAND_DELTA_VALUE = 5; private static MeteringCore instance; public static MeteringCore getInstance() { if (instance == null) instance = new MeteringCore(); return instance; } protected Map<String, ApplianceInfo> appliances = new ConcurrentHashMap<String, ApplianceInfo>(); protected IOnOffProxy onOffProxy; protected IMeteringProxy meteringProxy; protected ICloudServiceProxy cloudProxy = dummyCloudProxy; private OverloadStatus currentOverloadStatus = OverloadStatus.NoOverloadWarning; private IOverloadStatusListener overloadStatusListener = dummyOverloadListener; protected DailyTariff dailyTariff; protected PowerThresholds powerThresholds = new PowerThresholds(3000); protected float peakProducedPower = 0; // Watts/Hour protected SmartMeterInfo smartInfoExchange; protected SmartMeterInfo smartInfoProduction; protected boolean checkMeteringSubscriptions = true; protected long smartInfoPollingTimeInterval = SMART_INFO_POLLING_NORMAL_INTERVAL_MILLISEC; protected long lastSmartInfoPollingTime = 0; protected MeteringCore() { try { dailyTariff = DailyTariff.getInstance(); setCloudServiceProxy(null); } catch (Exception e) { e.printStackTrace(); } } private void refreshCurrentSummationDeliveredSubscription(ApplianceInfo appliance) { float formatting = getOrRetrieveSummationFormatting(appliance); if (formatting != IMeteringProxy.INVALID_FORMATTING_VALUE) { long minReportingInterval = 0; long maxReportingInterval = 0; double deltaValue = 0; DeviceType type = appliance.getApplianceType(); if (type == DeviceType.Meter) { minReportingInterval = SMART_INFO_SUMMATION_MIN_INTERVAL; maxReportingInterval = SMART_INFO_SUMMATION_MAX_INTERVAL; deltaValue = SMART_INFO_SUMMATION_DELTA_VALUE / formatting; } else { minReportingInterval = DEFAULT_SUMMATION_MIN_INTERVAL; maxReportingInterval = DEFAULT_SUMMATION_MAX_INTERVAL; deltaValue = DEFAULT_SUMMATION_DELTA_VALUE / formatting; } String applianceId = appliance.getApplianceId(); meteringProxy.subscribeCurrentSummationDelivered(applianceId, minReportingInterval, maxReportingInterval, deltaValue); if (checkMeteringSubscriptions) { double summation = meteringProxy.getCurrentSummationDelivered(applianceId); notifyCurrentSummationDelivered(applianceId, System.currentTimeMillis(), summation); // TODO: complete/review logging log.info("refreshCurrentSummationDeliveredSubscription - read power and summation for appliance " + applianceId + ": summation=" + summation); } } } private void refreshCurrentSummationReceivedSubscription(ApplianceInfo appliance) { float formatting = getOrRetrieveSummationFormatting(appliance); if (formatting != IMeteringProxy.INVALID_FORMATTING_VALUE) { double deltaValue = SMART_INFO_SUMMATION_DELTA_VALUE / formatting; String applianceId = appliance.getApplianceId(); meteringProxy.subscribeCurrentSummationReceived(applianceId, SMART_INFO_SUMMATION_MIN_INTERVAL, SMART_INFO_SUMMATION_MAX_INTERVAL, deltaValue); if (checkMeteringSubscriptions) { double summation = meteringProxy.getCurrentSummationReceived(applianceId); notifyCurrentSummationReceived(applianceId, System.currentTimeMillis(), summation); // TODO: complete/review logging log.info("refreshCurrentSummationReceivedSubscription - read power and summation for appliance " + applianceId + ": received=" + summation); } } } private void refreshInstantaneousDemandSubscription(ApplianceInfo appliance) { float formatting = getOrRetrieveDemandFormatting(appliance); if (formatting != IMeteringProxy.INVALID_FORMATTING_VALUE) { long minReportingInterval = 0; long maxReportingInterval = 0; float deltaValue = 0; if (appliance.getApplianceType() == DeviceType.Meter) { minReportingInterval = SMART_INFO_INST_DEMAND_MIN_INTERVAL; maxReportingInterval = SMART_INFO_INST_DEMAND_MAX_INTERVAL; deltaValue = SMART_INFO_INST_DEMAND_DELTA_VALUE / formatting; } else { minReportingInterval = DEFAULT_INST_DEMAND_MIN_INTERVAL; maxReportingInterval = DEFAULT_INST_DEMAND_MAX_INTERVAL; deltaValue = DEFAULT_INST_DEMAND_DELTA_VALUE / formatting; } String applianceId = appliance.getApplianceId(); meteringProxy.subscribeIstantaneousDemand(applianceId, minReportingInterval, maxReportingInterval, deltaValue); if (checkMeteringSubscriptions) { float power = meteringProxy.getIstantaneousDemand(applianceId); notifyIstantaneousDemandPower(applianceId, System.currentTimeMillis(), power); // TODO: complete/review logging log.info("refreshInstantaneousDemandSubscription - read power and summation for appliance " + applianceId + ": power=" + power); } } } private void checkOverloadStatus() { // The following formula takes into accounts monitored appliances instantaneous power consumptions data float signedPower = getTotalIstantaneousDemandPower() - (getIstantaneousProducedPower() - getIstantaneousSoldPower()); // Update smart infos polling frequency depending on current instantaneous delivered power if (signedPower >= powerThresholds.getNextToContractualThreshold()) { smartInfoPollingTimeInterval = SMART_INFO_POLLING_MIN_INTERVAL_MILLISEC; } else { smartInfoPollingTimeInterval = SMART_INFO_POLLING_NORMAL_INTERVAL_MILLISEC; } // Generate overload warnings depending on current instantaneous delivered power try { if (signedPower <= powerThresholds.getContractualThreshold() && !currentOverloadStatus.equals(OverloadStatus.NoOverloadWarning)) { currentOverloadStatus = OverloadStatus.NoOverloadWarning; overloadStatusListener.notifyOverloadStatusUpdate(currentOverloadStatus); } else if (signedPower > powerThresholds.getContractualThreshold() && signedPower <= powerThresholds.getFirstThreshold() && !currentOverloadStatus.equals(OverloadStatus.ContractualPowerThresholdWarning)) { currentOverloadStatus = OverloadStatus.ContractualPowerThresholdWarning; overloadStatusListener.notifyOverloadStatusUpdate(currentOverloadStatus); } else if (signedPower > powerThresholds.getFirstThreshold() && signedPower <= powerThresholds.getSecondThreshold() && !currentOverloadStatus.equals(OverloadStatus.FirstPowerThresholdWarning)) { currentOverloadStatus = OverloadStatus.FirstPowerThresholdWarning; overloadStatusListener.notifyOverloadStatusUpdate(currentOverloadStatus); } else if (signedPower > powerThresholds.getSecondThreshold() && !currentOverloadStatus.equals(OverloadStatus.SecondPowerThresholdWarning)) { currentOverloadStatus = OverloadStatus.SecondPowerThresholdWarning; overloadStatusListener.notifyOverloadStatusUpdate(currentOverloadStatus); } } catch (Exception e) { log.error("checkSmartInfosData error while checking wanrings", e); } } public void periodicTask() { log.debug(String.format("Periodic task: %s", appliances)); if (checkMeteringSubscriptions) { for (ApplianceInfo appliance : appliances.values()) { if (appliance.isAvailable()) { try { // check if last notifications are still valid, if not renew subscriptions // peakProducedPower > 0 means there is a solar panel if ((appliance == smartInfoExchange || appliance == smartInfoProduction) && peakProducedPower > 0) { if (System.currentTimeMillis() - ((SmartMeterInfo) appliance).getProducedEnergyTime() > 1500 * DEFAULT_SUMMATION_MAX_INTERVAL) { log.error(String.format( "Periodic task - invalid current summation received subscription for appliance %s", appliance.getApplianceId())); refreshCurrentSummationReceivedSubscription(appliance); } } if (smartInfoProduction != appliance) { if (System.currentTimeMillis() - appliance.getAccumulatedEnergyTime() > 1500 * DEFAULT_SUMMATION_MAX_INTERVAL) { log.error(String.format( "Periodic task - invalid current summation delivered subscription for appliance %s", appliance.getApplianceId())); refreshCurrentSummationDeliveredSubscription(appliance); } if (System.currentTimeMillis() - appliance.getIstantaneousPowerTime() > 1500 * DEFAULT_INST_DEMAND_MAX_INTERVAL) { log.error(String.format( "Periodic task - invalid instantaneous demand subscription for appliance %s", appliance.getApplianceId())); refreshInstantaneousDemandSubscription(appliance); } } } catch (Exception e) { log.error(String.format( "Periodic task error while initializing subscriptions for appliance %s", appliance.getApplianceId()), e); } } } } // Send requests to smart infos depending on current polling frequency try { if (System.currentTimeMillis() - lastSmartInfoPollingTime >= smartInfoPollingTimeInterval) { if (smartInfoExchange != null && smartInfoExchange.isAvailable()) { smartInfoExchange.setNextTotalEnergyValidValues(1); smartInfoExchange.setNextProducedEnergyValidValues(1); meteringProxy.getIstantaneousDemand(smartInfoExchange.getApplianceId()); } if (smartInfoProduction != null && smartInfoProduction.isAvailable()) { smartInfoProduction.setNextTotalEnergyValidValues(1); smartInfoProduction.setNextProducedEnergyValidValues(1); meteringProxy.getIstantaneousDemand(smartInfoProduction.getApplianceId()); } lastSmartInfoPollingTime = System.currentTimeMillis(); } } catch (Exception e) { log.error("periodicTask error while reading smart info instantaneous demand", e); } // Always update forecast data for hourly produced energy (data are cached by cloudProxy locally) if (smartInfoProduction != null) cloudProxy.retrieveHourlyProducedEnergyForecast(smartInfoProduction.getApplianceId()); } public IMeteringProxy getMeteringProxy() { return meteringProxy; } public void setMeteringProxy(IMeteringProxy proxy) { if (proxy == null) throw new IllegalArgumentException("The argument cannot be null."); meteringProxy = proxy; } public IOnOffProxy getOnOffProxy() { return onOffProxy; } public void setOnOffProxy(IOnOffProxy proxy) { if (proxy == null) throw new IllegalArgumentException("The argument cannot be null."); this.onOffProxy = proxy; } public ICloudServiceProxy getCloudServiceProxy() { return cloudProxy; } public void setCloudServiceProxy(ICloudServiceProxy proxy) { if (proxy != null) cloudProxy = proxy; else cloudProxy = dummyCloudProxy; } public IOverloadStatusListener getOverloadStatusListener() { return overloadStatusListener; } public void setOverloadStatusListener(IOverloadStatusListener listener) { if (listener != null) overloadStatusListener = listener; else overloadStatusListener = dummyOverloadListener; } public Class<? extends DailyTariff> getDailyTariff() { return dailyTariff.getClass(); } public void setDailyTariff(Class<? extends DailyTariff> clazz) throws InstantiationException, IllegalAccessException { dailyTariff = DailyTariff.getInstance(clazz); } public PowerThresholds getPowerThresholds() { return powerThresholds; } public void setPowerThresholds(PowerThresholds thresholds) { powerThresholds = thresholds; } public float getPeakProducedPower() { return peakProducedPower; } public void setPeakProducedPower(float upper) { peakProducedPower = upper; } public void setCheckMeteringSubscriptions(boolean enabled) { checkMeteringSubscriptions = enabled; } public ApplianceInfo getApplianceInfo(String applianceId) { return appliances.get(applianceId); } /*************************************************************************************************************************** * (non-Javadoc) * * @throws M2MHapException * @see org.energy_home.jemma.ah.ebrain.IMeteringListener */ // BEWARE: all notification values are raw data that need to be multiplied // by the relative formatting public void notifyIstantaneousDemandPower(String applianceId, long time, float power) { ApplianceInfo appliance = getApplianceInfo(applianceId); // instantaneous demand values are discarded for production smart info if (appliance == smartInfoProduction) return; if (power == IMeteringProxy.INVALID_INSTANTANEOUS_POWER_VALUE || power == IMeteringProxy.INVALID_INSTANTANEOUS_POWER_STANDARD_VALUE) { log.warn(String.format("Invalid Instantaneous Demand %f, from %s, at %s", power, applianceId, CalendarUtil.toSecondString(time))); try { cloudProxy.storeEvent(applianceId, time, ICloudServiceProxy.EVENT_INVALID_INST_DEMAND_VALUE); } catch (Exception e) { log.error("Error while storing event on HAP platform", e); } } else { float formatting = getOrRetrieveDemandFormatting(appliance); if (formatting != IMeteringProxy.INVALID_FORMATTING_VALUE) power *= formatting; else power = IMeteringProxy.INVALID_INSTANTANEOUS_POWER_VALUE; } appliance.setIstantaneousPower(power, time); checkOverloadStatus(); } // BEWARE: all notification values are raw data that need to be multiplied // by the relative formatting public void notifyCurrentSummationDelivered(String applianceId, long time, double totalEnergy) { ApplianceInfo appliance = getApplianceInfo(applianceId); // current summation delivered values are discarded for production smartinfo if (appliance == smartInfoProduction) return; if (totalEnergy == IMeteringProxy.INVALID_ENERGY_CONSUMPTION_VALUE) { log.warn(String.format("Invalid Current Summation %f, from %s, at %s", totalEnergy, applianceId, CalendarUtil.toSecondString(time))); try { cloudProxy.storeEvent(applianceId, time, ICloudServiceProxy.EVENT_INVALID_CURRENT_SUMMATION_DELIVERED_VALUE); } catch (Exception e) { log.error("Error while storing event on HAP platform", e); } } else { float formatting = getOrRetrieveSummationFormatting(appliance); if (formatting != IMeteringProxy.INVALID_FORMATTING_VALUE) totalEnergy *= formatting; else totalEnergy = IMeteringProxy.INVALID_ENERGY_CONSUMPTION_VALUE; } log.info(String.format("Current summation delivered %f, from %s, at %s", totalEnergy, applianceId, CalendarUtil.toSecondString(time))); if (totalEnergy != IMeteringProxy.INVALID_ENERGY_CONSUMPTION_VALUE) { try { cloudProxy.storeDeliveredEnergy(applianceId, time, totalEnergy); } catch (Exception e) { log.error("Error while storing delivered energy on HAP platform", e); } } EnergyCostInfo eci = appliance.updateEnergyCost(time, totalEnergy); if (eci != null && eci.isValid()) { MinMaxPowerInfo powerInfo = appliance.getMinMaxPowerInfo(); try { cloudProxy.storeDeliveredEnergyCostPowerInfo(applianceId, eci, powerInfo); } catch (Exception e) { log.error("Error while storing energy cost power info on HAP platform", e); } } } // this method is only called by a smartInfo, either production or exchange public void notifyCurrentSummationReceived(String applianceId, long time, double totalEnergy) { SmartMeterInfo appliance = (SmartMeterInfo) getApplianceInfo(applianceId); if (totalEnergy == IMeteringProxy.INVALID_ENERGY_CONSUMPTION_VALUE) { log.warn(String.format("Invalid Current Summation %f, from %s, at %s", totalEnergy, applianceId, CalendarUtil.toSecondString(time))); try { cloudProxy.storeEvent(applianceId, time, ICloudServiceProxy.EVENT_INVALID_CURRENT_SUMMATION_RECEIVED_VALUE); } catch (Exception e) { log.error("Error while storing event on HAP platform", e); } } else { float formatting = getOrRetrieveSummationFormatting(appliance); if (formatting != IMeteringProxy.INVALID_FORMATTING_VALUE) totalEnergy *= formatting; else totalEnergy = IMeteringProxy.INVALID_ENERGY_CONSUMPTION_VALUE; } log.info(String.format("Current summation received %f, from %s, at %s", totalEnergy, applianceId, CalendarUtil.toSecondString(time))); if (totalEnergy != IMeteringProxy.INVALID_ENERGY_CONSUMPTION_VALUE) { try { cloudProxy.storeReceivedEnergy(applianceId, time, totalEnergy); } catch (Exception e) { log.error("Error while storing received energy on HAP platform", e); } } EnergyCostInfo eci = appliance.updateProducedEnergy(time, totalEnergy); if (eci != null && eci.isValid()) { MinMaxPowerInfo powerInfo = appliance.getMinMaxPowerInfo(); try { cloudProxy.storeReceivedEnergyCostPowerInfo(applianceId, eci, powerInfo); } catch (Exception e) { log.error("Error while storing energy cost power info on HAP platform", e); } } } public double getCurrentSummationReceived(String applianceId) { // TODO Auto-generated method stub return 0; } /* * public MinMaxPowerInfo getInstantaneosPowerInfo(String applianceId) { * ApplianceInfo appliance = getApplianceInfo(applianceId); * * if (appliance != smartInfo) return appliance.getMinMaxPowerInfo(); * * // ENEL fix: we need to see if the current total power is greater than * the sum of all smart appliances float summedPower = 0; MinMaxPowerInfo * totalPower = smartInfo.getMinMaxPowerInfo(); * * // start by setting the sum with the negative of the smart-info value, as * it will be added again in the next loop // and we don't want that * summedPower = -smartInfo.getIstantaneousPower(); for (ApplianceInfo a : * appliances.values()) { summedPower += a.getIstantaneousPower(); } * * if (totalPower.getCurrentPower() < summedPower) { * totalPower.setCurrentPower(summedPower, System.currentTimeMillis()); } * return totalPower; } * * * public double getApplianceAccumulatedEnergy(String applianceId) { * ApplianceInfo appliance = getApplianceInfo(applianceId); return * appliance.getAccumulatedEnergy(); } * * * public long getApplianceAccumulatedEnergyTime(String applianceId) { * ApplianceInfo appliance = getApplianceInfo(applianceId); return * appliance.getAccumulatedEnergyTime(); } */ public String getSmartInfoExchangeId() { if (smartInfoExchange == null) return null; return smartInfoExchange.getApplianceId(); } public String getSmartInfoProductionId() { if (smartInfoProduction == null) return null; return smartInfoProduction.getApplianceId(); } public float getIstantaneousProducedPower() { if (smartInfoProduction == null) return 0; float producedPower = smartInfoProduction.getMeanProducedPower(); //float producedPower = (float) smartInfoProduction.getProducedEnergy(); if (producedPower > peakProducedPower) { log.error("Produced power greater than configured peak power"); producedPower = peakProducedPower; } return producedPower; } public float getIstantaneousSoldPower() { if (smartInfoExchange == null) return 0; float soldPower = smartInfoExchange.getMeanProducedPower(); if (soldPower > peakProducedPower) { log.error("Sold power greater than configured peak power"); soldPower = peakProducedPower; } return soldPower; } public float getTotalIstantaneousDemandPower() { // ENEL fix: check if the current total power is greater than the sum of // all smart appliances float totalPower = 0; if (smartInfoExchange != null) totalPower = smartInfoExchange.getIstantaneousPower() + getIstantaneousProducedPower() - getIstantaneousSoldPower(); if (totalPower < 0) totalPower = 0; float summedPower = 0; for (ApplianceInfo a : appliances.values()) { if (a != smartInfoExchange && a != smartInfoProduction) summedPower += a.getIstantaneousPower(); } return Math.max(summedPower, totalPower); } public float getIstantaneousDemandPower(String applianceId) { ApplianceInfo appliance = getApplianceInfo(applianceId); return appliance.getIstantaneousPower(); } public double getCurrentSummationDelivered(String applianceId) { ApplianceInfo appliance = getApplianceInfo(applianceId); return appliance.getAccumulatedEnergy(); } public EnergyCostInfo getAccumulatedEnergyCost(String applianceId) { ApplianceInfo appliance = getApplianceInfo(applianceId); return appliance.getAccumulatedEnergyCost(); } private float getOrRetrieveSummationFormatting(ApplianceInfo appliance) { float formatting = appliance.getSummationFormatting(); if (formatting == IMeteringProxy.INVALID_FORMATTING_VALUE) { formatting = meteringProxy.getSummationFormatting(appliance.getApplianceId()); appliance.setSummationFormatting(formatting); } return formatting; } private float getOrRetrieveDemandFormatting(ApplianceInfo appliance) { float formatting = appliance.getDemandFormatting(); if (formatting == IMeteringProxy.INVALID_FORMATTING_VALUE) { formatting = meteringProxy.getDemandFormatting(appliance.getApplianceId()); appliance.setDemandFormatting(formatting); } return formatting; } public String getEndPointId() { return "EnergyBrain"; } public void notifyDeviceAdded(DeviceInfo info) { String applianceId = info.getPersistentId(); ApplianceInfo appliance = appliances.get(applianceId); if (appliance == null) { if (info.getConfiguration().getCategory() == DeviceCategory.Meter) { smartInfoExchange = new SmartMeterInfo(info); appliance = smartInfoExchange; } else if (info.getConfiguration().getCategory() == DeviceCategory.ProductionMeter) { smartInfoProduction = new SmartMeterInfo(info); appliance = smartInfoProduction; } else { appliance = new ApplianceInfo(info); } appliances.put(applianceId, appliance); } if (appliance.getAccumulatedEnergyTime() == 0) { ContentInstance ci = cloudProxy.retrieveDeliveredEnergySummation(applianceId); if (ci != null) { Long timestamp = ci.getId(); Double energySummation = (Double) ci.getContent(); appliance.updateEnergyCost(timestamp.longValue(), energySummation.doubleValue()); } } if (appliance == smartInfoExchange) { smartInfoExchange.setNextTotalEnergyValidValues(0); smartInfoExchange.setNextProducedEnergyValidValues(0); } else if (appliance == smartInfoProduction) { smartInfoProduction.setNextTotalEnergyValidValues(0); smartInfoProduction.setNextProducedEnergyValidValues(0); } } public void notifyDeviceRemoved(DeviceInfo info) { String applianceId = info.getPersistentId(); if (smartInfoExchange != null && applianceId.equals(smartInfoExchange.getApplianceId())) { smartInfoExchange = null; } else if (smartInfoProduction != null && applianceId.equals(smartInfoProduction.getApplianceId())) { smartInfoProduction = null; } appliances.remove(applianceId); } public void notifyDeviceDescriptorUpdated(DeviceInfo info) { } public void notifyDeviceConfigurationUpdated(DeviceInfo info) { } protected void deviceAvailabilityUpdated(String applianceId, boolean isAvailable) { ApplianceInfo appliance = getApplianceInfo(applianceId); appliance.setAvailable(isAvailable); if (appliance.isAvailable()) { if (appliance != smartInfoProduction) { refreshCurrentSummationDeliveredSubscription(appliance); refreshInstantaneousDemandSubscription(appliance); } if ((appliance == smartInfoProduction || appliance == smartInfoExchange) && peakProducedPower > 0) { refreshCurrentSummationReceivedSubscription(appliance); } } else { appliance.setIstantaneousPower(0, System.currentTimeMillis()); } } public void notifyDeviceServiceAvailable(DeviceInfo info, DeviceService deviceService) { String applianceId = info.getPersistentId(); deviceAvailabilityUpdated(applianceId, true); } public void notifyDeviceServiceUnavailable(DeviceInfo info) { String applianceId = info.getPersistentId(); deviceAvailabilityUpdated(applianceId, false); } }