/* ================================================================== * PanasonicBatteryDatumDataSource.java - 16/02/2016 8:19:50 pm * * Copyright 2007-2016 SolarNetwork.net Dev Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * ================================================================== */ package net.solarnetwork.node.datum.panasonic.battery; import java.util.List; import java.util.Locale; import net.solarnetwork.node.DatumDataSource; import net.solarnetwork.node.domain.EnergyStorageDatum; import net.solarnetwork.node.domain.GeneralNodeEnergyStorageDatum; import net.solarnetwork.node.hw.panasonic.battery.BatteryAPIException; import net.solarnetwork.node.hw.panasonic.battery.BatteryAPISupport; import net.solarnetwork.node.hw.panasonic.battery.BatteryData; import net.solarnetwork.node.settings.SettingSpecifier; import net.solarnetwork.node.settings.SettingSpecifierProvider; import net.solarnetwork.node.settings.support.BasicTextFieldSettingSpecifier; import org.joda.time.DateTime; import org.springframework.context.MessageSource; /** * {@link DatumDataSource} implementation for * {@link GeneralNodeEnergyStorageDatum} with the Panasonic Battery API. * * <p> * The configurable properties of this class are: * </p> * * <dl class="class-properties"> * <dt>messageSource</dt> * <dd>The {@link MessageSource} to use with {@link SettingSpecifierProvider}.</dd> * * <dt>sampleCacheMs</dt> * <dd>The maximum number of milliseconds to cache data read from the battery * API, until the data will be read from the API again.</dd> * </dl> * * @author matt * @version 1.0 */ public class PanasonicBatteryDatumDataSource extends BatteryAPISupport implements DatumDataSource<GeneralNodeEnergyStorageDatum>, SettingSpecifierProvider { private String email; private String deviceID; private MessageSource messageSource; private long sampleCacheMs = 5000; private String sourceId = "Battery"; private synchronized BatteryData getCurrentSample() { final String user = getEmail(); final String id = getDeviceID(); final boolean useDeviceID = (id != null && id.length() > 0); if ( (user == null || user.length() < 1) && !useDeviceID ) { log.info("No device ID or email configured, cannot collect sample."); return null; } BatteryData currSample = sample; if ( isCachedSampleExpired() ) { try { if ( useDeviceID ) { currSample = getClient().getCurrentBatteryDataForDevice(id); } else { currSample = getClient().getCurrentBatteryDataForEmail(user); } setErrorMessage(null); sample = currSample; } catch ( BatteryAPIException e ) { String msg = null; if ( e.getCode() > 0 ) { switch (e.getCode()) { case 404: if ( useDeviceID ) { msg = getMessageSource().getMessage("error.code.404.device", new Object[] { id }, Locale.getDefault()); } else { msg = getMessageSource().getMessage("error.code.404.email", new Object[] { user }, Locale.getDefault()); } break; default: msg = getMessageSource().getMessage("error.code", new Object[] { e.getCode() }, Locale.getDefault()); break; } } else { msg = "Error communicating with Battery API: " + e.getMessage(); } setErrorMessage(msg); if ( e.getCode() > 0 ) { log.warn("Battery API server returned error code {}", e.getCode()); return null; } else { throw e; } } log.debug("Read BatteryData sample: {}", currSample); } return currSample; } private boolean isCachedSampleExpired() { final DateTime sampleDate = (sample != null ? sample.getDate() : null); if ( sampleDate == null ) { return true; } final long lastReadDiff = System.currentTimeMillis() - sampleDate.getMillis(); if ( lastReadDiff > sampleCacheMs ) { return true; } return false; } @Override public Class<? extends GeneralNodeEnergyStorageDatum> getDatumType() { return PanasonicBatteryDatum.class; } @Override public GeneralNodeEnergyStorageDatum readCurrentDatum() { final long start = System.currentTimeMillis(); final BatteryData currSample = getCurrentSample(); if ( currSample == null ) { return null; } PanasonicBatteryDatum d = new PanasonicBatteryDatum(currSample); d.setSourceId(getSourceId()); if ( currSample.getDate() != null && currSample.getDate().getMillis() >= start ) { // we read from the meter postDatumCapturedEvent(d, EnergyStorageDatum.class); } return d; } // SettingSpecifierProvider @Override public String getSettingUID() { return "net.solarnetwork.node.datum.panasonic.battery"; } @Override public String getDisplayName() { return "Panasonic Battery API Battery"; } public void setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; } @Override public MessageSource getMessageSource() { return messageSource; } @Override public List<SettingSpecifier> getSettingSpecifiers() { PanasonicBatteryDatumDataSource defaults = new PanasonicBatteryDatumDataSource(); List<SettingSpecifier> results = super.getSettingSpecifiers(); results.add(new BasicTextFieldSettingSpecifier("deviceID", "")); results.add(new BasicTextFieldSettingSpecifier("email", "")); results.add(new BasicTextFieldSettingSpecifier("sourceId", String.valueOf(defaults.getSourceId()))); results.add(new BasicTextFieldSettingSpecifier("sampleCacheMs", String.valueOf(defaults .getSampleCacheMs()))); return results; } @Override public String toString() { String key = "deviceID"; String ident = getDeviceID(); if ( ident == null || ident.length() < 1 ) { key = "email"; ident = getEmail(); } return getClass().getSimpleName() + "{" + key + "=" + (ident != null ? ident : "") + "}"; } /** * Get the sample cache maximum age, in milliseconds. * * @return the cache milliseconds */ public long getSampleCacheMs() { return sampleCacheMs; } /** * Set the sample cache maximum age, in milliseconds. * * @param sampleCacheSecondsMs * the cache milliseconds */ public void setSampleCacheMs(long sampleCacheMs) { this.sampleCacheMs = sampleCacheMs; } /** * Get the email address used with the Battery API. * * @return The configured email. */ public String getEmail() { return email; } /** * Set the email address to use with the Battery API. This must be the same * as the email registered with Panasonic. * * @param email * The email address to use. */ public void setEmail(String email) { this.email = email; } /** * Get the battery device ID to use with the Battery API. Either this or * {@link #getEmail()} must be configured, with this value being used in * preference to the other. * * @return The configured battery device ID. */ public String getDeviceID() { return deviceID; } /** * Set the battery device ID to use with the Battery API. * * @param deviceID * The battery device ID to use. */ public void setDeviceID(String deviceID) { this.deviceID = deviceID; } /** * Get the source ID to assign to generated datum. * * @return The configured source ID. */ public String getSourceId() { return sourceId; } /** * Set the source ID to assign to generated datum. * * @param sourceId * The source ID to use. */ public void setSourceId(String sourceId) { this.sourceId = sourceId; } }