/*
* Dog - EnOcean Temperature Sensor Driver
*
* Copyright 2015 Dario Bonino
*
* 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 org.doggateway.drivers.enocean.temperaturesensor;
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.Controllable;
import it.polito.elite.dog.core.library.model.devicecategory.SingleTemperatureSensor;
import it.polito.elite.dog.core.library.model.state.TemperatureState;
import it.polito.elite.dog.core.library.model.statevalue.TemperatureStateValue;
import it.polito.elite.dog.core.library.util.LogHelper;
import it.polito.elite.enocean.enj.eep.EEPAttribute;
import it.polito.elite.enocean.enj.eep.eep26.attributes.EEP26TemperatureInverseLinear;
import it.polito.elite.enocean.enj.model.EnOceanDevice;
import javax.measure.DecimalMeasure;
import javax.measure.Measure;
import javax.measure.unit.SI;
import javax.measure.unit.UnitFormat;
import org.doggateway.drivers.enocean.network.EnOceanDriverInstance;
import org.doggateway.drivers.enocean.network.info.EnOceanDeviceInfo;
import org.doggateway.drivers.enocean.network.interfaces.EnOceanNetwork;
import org.osgi.framework.BundleContext;
import org.osgi.service.log.LogService;
/**
* <p>
* Implements the actual handling, in Dog, of EnOcean devices having an EEP in
* the A502XX family. Takes care of registering needed listeners and hooks to
* both the network and gateway driver and, handles status updates and
* notifications for corresponding devices in Dog.
* </p>
*
* @author <a href="mailto:dario.bonino@gmail.com">Dario Bonino</a>
*
*/
public class TemperatureSensorDriverInstance extends EnOceanDriverInstance
implements SingleTemperatureSensor
{
// the class logger
private LogHelper logger;
/**
* Class constructor, builds a fully functional instance of Single
* Temperature Sensor driver
*
* @param enOceanNetwork
* The EnOcean network driver used to access the low-level
* network infrastructure
* @param device
* The Dog device to which this instance shall be connected
* @param updateTimeMillis
* The required update time in millis (not needed inthis case)
* @param context
* The bundle context to perform any needed operation involving
* the OSGi Framework (e.g., logging)
*/
public TemperatureSensorDriverInstance(EnOceanNetwork enOceanNetwork,
ControllableDevice device, int updateTimeMillis,
BundleContext context)
{
// call the superclass constructor
super(enOceanNetwork, device);
// create a logger
this.logger = new LogHelper(context);
// initialize the temperature sensor states
this.initializeStates();
}
/*
* (non-Javadoc)
*
* @see
* it.polito.elite.dog.core.library.model.devicecategory.TemperatureSensor
* #getState()
*/
@Override
public DeviceStatus getState()
{
// provides back the current state of the device
return this.currentState;
}
/*
* (non-Javadoc)
*
* @see org.doggateway.drivers.enocean.network.EnOceanDriverInstance#
* specificConfiguration()
*/
@Override
protected void specificConfiguration()
{
// prepare the device state map
this.currentState = new DeviceStatus(device.getDeviceId());
}
/*
* (non-Javadoc)
*
* @see org.doggateway.drivers.enocean.network.EnOceanDriverInstance#
* addToNetworkDriver
* (org.doggateway.drivers.enocean.network.info.EnOceanDeviceInfo)
*/
@Override
protected void addToNetworkDriver(EnOceanDeviceInfo device)
{
// register this driver as handler for the device described by the given
// device info.
this.network.addDriver(device, this);
}
/*
* (non-Javadoc)
*
* @see
* org.doggateway.drivers.enocean.network.EnOceanDriverInstance#bindDevice
* (it.polito.elite.enocean.enj.model.EnOceanDevice)
*/
@Override
protected void bindDevice(EnOceanDevice device)
{
// called when the given device is "attached" at the network level, used
// for registering listeners
// double check
if (device.getDeviceUID() == this.theManagedDevice.getUid())
{
// store the low level device
this.theLowLevelDevice = device;
// register eep listeners
this.theLowLevelDevice.getEEP().addEEP26AttributeListener(0,
EEP26TemperatureInverseLinear.NAME, this);
}
}
/*
* (non-Javadoc)
*
* @see
* org.doggateway.drivers.enocean.network.EnOceanDriverInstance#unBindDevice
* (it.polito.elite.enocean.enj.model.EnOceanDevice)
*/
@Override
protected void unBindDevice(EnOceanDevice device)
{
// double check
if (device.getDeviceUID() == this.theManagedDevice.getUid())
{
// remove the listener
this.theLowLevelDevice.getEEP().removeEEP26AttributeListener(0,
EEP26TemperatureInverseLinear.NAME, this);
// null the low level device
this.theLowLevelDevice = null;
}
}
@Override
public Measure<?, ?> getTemperature()
{
// provides back the current temperature
return (Measure<?, ?>) this.currentState.getState(
TemperatureState.class.getSimpleName()).getCurrentStateValue()[0]
.getValue();
}
@Override
public void deleteGroup(Integer groupID)
{
// Currently not supported
}
@Override
public void storeGroup(Integer groupID)
{
// Currently not supported
}
@Override
public void notifyNewTemperatureValue(Measure<?, ?> temperatureValue)
{
((SingleTemperatureSensor) this.device)
.notifyNewTemperatureValue(temperatureValue);
}
@Override
public void notifyJoinedGroup(Integer groupNumber)
{
((SingleTemperatureSensor) this.device).notifyJoinedGroup(groupNumber);
}
@Override
public void notifyLeftGroup(Integer groupNumber)
{
((SingleTemperatureSensor) this.device).notifyLeftGroup(groupNumber);
}
/*
* (non-Javadoc)
*
* @see it.polito.elite.enocean.enj.eep.EEPAttributeChangeListener#
* handleAttributeChange(int, it.polito.elite.enocean.enj.eep.EEPAttribute)
*/
@Override
public void handleAttributeChange(int channelId, EEPAttribute<?> attribute)
{
// handle the attribute change
if (attribute instanceof EEP26TemperatureInverseLinear)
{
// get the attribute vakue
EEP26TemperatureInverseLinear temperature = (EEP26TemperatureInverseLinear) attribute;
// the temperature value as a double
Double value = (Double) temperature.getValue();
// the unit of measure (Celsius)
String unit = temperature.getUnit(); // always Celsius
// update and notify
this.updateAndNotify(value, unit);
}
}
/*
* (non-Javadoc)
*
* @see
* it.polito.elite.dog.core.library.model.devicecategory.TemperatureSensor
* #updateStatus()
*/
@Override
public void updateStatus()
{
((Controllable) this.device).updateStatus();
}
/**
* Prepare the data structures needed to model the device states, and fills
* it with the initial values.
*/
private void initializeStates()
{
// update the CELSIUS notation
UnitFormat uf = UnitFormat.getInstance();
uf.label(SI.CELSIUS, "C");
uf.alias(SI.CELSIUS, "C");
// the initial temperature value
TemperatureStateValue tValue = new TemperatureStateValue();
tValue.setValue(DecimalMeasure.valueOf("0 " + SI.CELSIUS.toString()));
// the initial state
TemperatureState tState = new TemperatureState(tValue);
// set the current state
this.currentState.setState(TemperatureState.class.getSimpleName(),
tState);
}
/**
* Updates the current status of the device handled by this driver instance
* and notifies any change
*
* @param value
* The temperature value to use for updating the state
* @param unit
* The unit of measure, "Celsius" in all currently implemented
* profiles
*/
private void updateAndNotify(Double value, String unit)
{
// check the unit
if ((unit != null)
&& (!unit.isEmpty())
&& ((unit.equalsIgnoreCase("Celsius")
|| unit.equalsIgnoreCase("°C") || unit
.equalsIgnoreCase("C"))))
{
// treat the temperature as a measure
DecimalMeasure<?> temperature = DecimalMeasure.valueOf(String.format("%.2f", value) + " "
+ SI.CELSIUS);
// update the current state
this.currentState.getState(TemperatureState.class.getSimpleName())
.getCurrentStateValue()[0].setValue(temperature);
// update the status (Monitor Admin)
this.updateStatus();
// notify the change
this.notifyNewTemperatureValue(temperature);
// log
this.logger.log(LogService.LOG_INFO,
"Device " + device.getDeviceId() + " temperature "
+ temperature.toString());
}
}
}