Implemented HalSensorController and HalSensorData RPiPowerConsumptionSensor

+ Added RPiTemperatureSensor
+ Updated pi4j-1.0 to pi4j-1.1-SNAPSHOT that includes support for 1-Wire communication and various sensors.


Former-commit-id: 6db4193283bf3fc604fcf250d7a321ba8b70b6a4
This commit is contained in:
Daniel Collin 2016-01-19 13:51:58 +01:00
parent 3884634590
commit e9d32dcc30
28 changed files with 453 additions and 171 deletions

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry excluding="" kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="lib" path="external/marytts-5.1.2/lib/icu4j-54.1.1.jar"/>
<classpathentry kind="lib" path="external/marytts-5.1.2/lib/marytts-client-5.1.2-jar-with-dependencies.jar"/>
@ -18,12 +18,31 @@
<classpathentry kind="lib" path="lib/commons-math3-3.5.jar"/>
<classpathentry kind="lib" path="lib/marytts-client-5.1.2-jar-with-dependencies.jar"/>
<classpathentry kind="lib" path="lib/marytts-runtime-5.1.2-jar-with-dependencies.jar"/>
<classpathentry kind="lib" path="lib/pi4j-core-1.0.jar"/>
<classpathentry kind="lib" path="lib/junit-4.12.jar"/>
<classpathentry kind="lib" path="lib/java-speech-api-master.jar"/>
<classpathentry kind="lib" path="lib/sphinx4-core.jar"/>
<classpathentry kind="lib" path="lib/sqlite-jdbc-3.8.11.2_HACKED_FOR_RPI.jar"/>
<classpathentry kind="lib" path="lib/jSerialComm-1.3.10.jar"/>
<classpathentry kind="lib" path="lib/pi4j-core-1.1-SNAPSHOT.jar" sourcepath="external/pi4j-1.1/pi4j-core-sources-1.1-SNAPSHOT.jar">
<attributes>
<attribute name="javadoc_location" value="jar:platform:/resource/hal/external/pi4j-1.1/pi4j-core-javadoc-1.1-SNAPSHOT.jar!/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="lib/pi4j-device-1.1-SNAPSHOT.jar" sourcepath="external/pi4j-1.1/pi4j-device-sources-1.1-SNAPSHOT.jar">
<attributes>
<attribute name="javadoc_location" value="jar:platform:/resource/hal/external/pi4j-1.1/pi4j-device-javadoc-1.1-SNAPSHOT.jar!/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="lib/pi4j-gpio-extension-1.1-SNAPSHOT.jar" sourcepath="external/pi4j-1.1/pi4j-gpio-extension-sources-1.1-SNAPSHOT.jar">
<attributes>
<attribute name="javadoc_location" value="jar:platform:/resource/hal/external/pi4j-1.1/pi4j-gpio-extension-javadoc-1.1-SNAPSHOT.jar!/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="lib/pi4j-service-1.1-SNAPSHOT.jar" sourcepath="external/pi4j-1.1/pi4j-service-sources-1.1-SNAPSHOT.jar">
<attributes>
<attribute name="javadoc_location" value="jar:platform:/resource/hal/external/pi4j-1.1/pi4j-service-javadoc-1.1-SNAPSHOT.jar!/"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/zutil-java"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>

View file

@ -24,16 +24,6 @@
<!-- ________________________ PUBLIC TARGETS ________________________ -->
<target name="run-local-sensor" depends="">
<java fork="true" failonerror="true" classname="se.hal.plugin.localsensor.RPiImpulseCountSensor">
<classpath>
<pathelement path="${buildDir}/hal.jar"/> <!--wildcard may not be platform independent, ok?-->
<pathelement path="${libDir}/*"/> <!--wildcard may not be platform independent, ok?-->
</classpath>
</java>
</target>
<target name="run-remote-sensor" depends="">
<java fork="true" failonerror="true" classname="se.hal.plugin.tellstick.TelstickSerialCommTest">
<classpath>
@ -86,5 +76,4 @@
<get src="http://repo.koc.se/zutil-java.git/blob/master/Zutil.jar" dest="${libDir}" verbose="true" usetimestamp="true"/>
</target>
</project>

View file

@ -0,0 +1 @@
f5f1233720cc2e51d8b732e5010df1018eefd115

Binary file not shown.

View file

@ -0,0 +1 @@
015ed72cae989b46deca43c6e4cc02fb2cbe6419

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,40 +0,0 @@
package se.hal.plugin.localsensor;
import se.hal.intf.HalSensorData;
import se.hal.intf.HalSensorController;
import se.hal.intf.HalSensorReportListener;
/**
* Created by ezivkoc on 2016-01-14.
*/
public class RPiController implements HalSensorController {
@Override
public void initialize() throws Exception {
}
@Override
public void register(HalSensorData sensor) {
}
@Override
public void deregister(HalSensorData sensor) {
}
@Override
public int size() {
return 0;
}
@Override
public void setListener(HalSensorReportListener listener) {
}
@Override
public void close() {
}
}

View file

@ -1,34 +0,0 @@
package se.hal.plugin.localsensor;
import se.hal.intf.HalSensorController;
import se.hal.struct.PowerConsumptionSensorData;
/**
* Created by ezivkoc on 2016-01-14.
*/
public class RPiSensor implements PowerConsumptionSensorData {
@Override
public long getTimestamp() {
return 0;
}
@Override
public double getData() {
return 0;
}
@Override
public AggregationMethod getAggregationMethod() {
return AggregationMethod.SUM;
}
@Override
public Class<? extends HalSensorController> getSensorController() {
return RPiController.class;
}
public boolean equals(Object obj){
return obj == this;
}
}

View file

@ -1,7 +0,0 @@
{
"version": 1.0,
"name": "RPiImpulsCountSensor",
"interfaces": [
{"se.hal.intf.HalSensorData": "se.hal.plugin.localsensor.RPiSensor"}
]
}

View file

@ -0,0 +1,102 @@
package se.hal.plugin.raspberry;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.pi4j.io.gpio.Pin;
import se.hal.intf.HalSensorData;
import se.hal.intf.HalSensorController;
import se.hal.intf.HalSensorReportListener;
import se.hal.plugin.raspberry.hardware.RPiDS18B20;
import se.hal.plugin.raspberry.hardware.RPiInteruptPulseFlankCounter;
import zutil.log.LogUtil;
public class RPiController implements HalSensorController {
private static final Logger logger = LogUtil.getLogger();
private HashMap<String, RPiSensor> pinToSensorMap = new HashMap<>();
private HalSensorReportListener sensorListener;
public RPiController(){
}
@Override
public void initialize() throws Exception {
}
@Override
public void register(HalSensorData sensor) {
if(sensor instanceof RPiPowerConsumptionSensor){
RPiPowerConsumptionSensor powerConsumprtionSensor = (RPiPowerConsumptionSensor) sensor;
Pin gpioPin = powerConsumprtionSensor.getGpioPin();
if(!pinToSensorMap.containsKey(gpioPin.getName())){
RPiInteruptPulseFlankCounter impulseCounter = new RPiInteruptPulseFlankCounter(gpioPin, this);
pinToSensorMap.put(gpioPin.getName(), impulseCounter);
}else{
logger.warning("Cannot create a RPiPowerConsumptionSensor on GPIO pin " + gpioPin + " since is already is in use by another sensor.");
}
} else if(sensor instanceof RPiTemperatureSensor){
RPiTemperatureSensor temperatureSensor = (RPiTemperatureSensor) sensor;
String w1Address = temperatureSensor.get1WAddress();
if(!pinToSensorMap.containsKey(w1Address)){
RPiDS18B20 ds12b20 = new RPiDS18B20(w1Address, this);
pinToSensorMap.put(w1Address, ds12b20);
}else{
logger.warning("Cannot create a RPi1WireTemperatureSensor on 1-Wire address " + w1Address + " since is already is in use by another sensor.");
}
}else{
logger.warning("Cannot register a non-supported sensor");
}
}
@Override
public void deregister(HalSensorData sensor) {
if(sensor instanceof RPiPowerConsumptionSensor){
RPiPowerConsumptionSensor powerConsumprtionSensor = (RPiPowerConsumptionSensor) sensor;
RPiSensor sensorToDeregister = pinToSensorMap.remove(powerConsumprtionSensor.getGpioPin().getName());
if(sensorToDeregister != null){
sensorToDeregister.close();
}
} else if(sensor instanceof RPiTemperatureSensor){
RPiTemperatureSensor temperatureSensor = (RPiTemperatureSensor) sensor;
RPiSensor sensorToDeregister = pinToSensorMap.remove(temperatureSensor.get1WAddress());
if(sensorToDeregister != null){
sensorToDeregister.close();
}
}else{
logger.warning("Cannot deregister a non-supported sensor");
return;
}
}
@Override
public int size() {
return pinToSensorMap.size();
}
@Override
public void setListener(HalSensorReportListener listener) {
sensorListener = listener;
}
@Override
public void close() {
for(String key : this.pinToSensorMap.keySet()){
pinToSensorMap.get(key).close();
pinToSensorMap.remove(key);
}
}
public void sendDataReport(HalSensorData sensorData){
if(sensorListener != null){
sensorListener.reportReceived(sensorData);
}else{
logger.log(Level.WARNING, "Could not report data. No registered listener");
}
}
}

View file

@ -0,0 +1,51 @@
package se.hal.plugin.raspberry;
import com.pi4j.io.gpio.Pin;
import se.hal.intf.HalSensorController;
import se.hal.struct.PowerConsumptionSensorData;
import zutil.ui.Configurator;
public class RPiPowerConsumptionSensor implements PowerConsumptionSensorData {
@Configurator.Configurable("GPIO-Pin")
private int gpioPin = -1;
private final double data;
private final long timestamp;
public RPiPowerConsumptionSensor(long timestamp, double data) {
this.timestamp = timestamp;
this.data = data;
}
@Override
public long getTimestamp() {
return timestamp;
}
@Override
public double getData() {
return data;
}
@Override
public AggregationMethod getAggregationMethod() {
return AggregationMethod.SUM;
}
@Override
public Class<? extends HalSensorController> getSensorController() {
return RPiController.class;
}
public boolean equals(Object obj){
if(obj instanceof RPiPowerConsumptionSensor)
return obj == this;
return false;
}
public Pin getGpioPin() {
return RPiUtility.getPin(gpioPin);
}
}

View file

@ -0,0 +1,7 @@
package se.hal.plugin.raspberry;
public interface RPiSensor {
void close();
}

View file

@ -0,0 +1,54 @@
package se.hal.plugin.raspberry;
import se.hal.intf.HalSensorController;
import se.hal.struct.TemperatureSensorData;
import zutil.ui.Configurator;
public class RPiTemperatureSensor implements TemperatureSensorData {
@Configurator.Configurable("1-Wire Address")
private String w1Address = null;
private final double data;
private final long timestamp;
public RPiTemperatureSensor(long timestamp, double data) {
this.timestamp = timestamp;
this.data = data;
}
@Override
public long getTimestamp() {
return timestamp;
}
@Override
public double getData() {
return data;
}
@Override
public AggregationMethod getAggregationMethod() {
return AggregationMethod.AVERAGE;
}
@Override
public Class<? extends HalSensorController> getSensorController() {
return RPiController.class;
}
public boolean equals(Object obj){
if(obj instanceof RPiTemperatureSensor)
return obj == this;
return false;
}
public String get1WAddress() {
return w1Address;
}
@Override
public double getTemperature() {
return data;
}
}

View file

@ -0,0 +1,75 @@
package se.hal.plugin.raspberry;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.RaspiPin;
public class RPiUtility {
public static Pin getPin(int gpioPin){
switch(gpioPin){
case 0:
return RaspiPin.GPIO_00;
case 1:
return RaspiPin.GPIO_01;
case 2:
return RaspiPin.GPIO_02;
case 3:
return RaspiPin.GPIO_03;
case 4:
return RaspiPin.GPIO_04;
case 5:
return RaspiPin.GPIO_05;
case 6:
return RaspiPin.GPIO_06;
case 7:
//used by 1-wire divices
case 8:
//used by I2C devices
case 9:
//used by I2C devices
case 10:
//used by SPI devices
case 11:
//used by SPI devices
case 12:
//used by SPI devices
case 13:
//used by SPI devices
case 14:
//used by SPI devices
case 15:
//used by Serial devices
case 16:
//used by Serial devices
case 17:
//reserved for future use
case 18:
//reserved for future use
case 19:
//reserved for future use
case 20:
//reserved for future use
case 21:
//reserved for future use
case 22:
//reserved for future use
case 23:
//reserved for future use
case 24:
//reserved for future use
case 25:
//reserved for future use
case 26:
//reserved for future use
case 27:
//reserved for future use
case 28:
//reserved for future use
case 29:
//reserved for future use
default:
return null;
}
}
}

View file

@ -0,0 +1,63 @@
package se.hal.plugin.raspberry.hardware;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import se.hal.plugin.raspberry.RPiTemperatureSensor;
import se.hal.plugin.raspberry.RPiController;
import se.hal.plugin.raspberry.RPiSensor;
import zutil.log.LogUtil;
import com.pi4j.component.temperature.TemperatureSensor;
import com.pi4j.io.w1.W1Master;
import com.pi4j.temperature.TemperatureScale;
public class RPiDS18B20 implements RPiSensor, Runnable {
private static final Logger logger = LogUtil.getLogger();
private final String DEGREE_SIGN = "\u00b0";
private RPiController controller;
private String w1Address;
private ScheduledExecutorService scheduler;
private W1Master w1Mater;
public RPiDS18B20(String w1Address, RPiController controller){
this.controller = controller;
this.w1Address = w1Address;
scheduler = Executors.newScheduledThreadPool(1);
w1Mater = new W1Master();
//print out all sensors found
for(TemperatureSensor device : w1Mater.getDevices(TemperatureSensor.class)){
logger.info(String.format("1-Wire temperature sensor divice found: %-20s: %3.1f"+DEGREE_SIGN+"C\n", device.getName(), device.getTemperature(TemperatureScale.CELSIUS)));
}
//schedule job
scheduler.scheduleAtFixedRate(this, 10, 60, TimeUnit.SECONDS); //wait 10s and run every 60s
}
public void close() {
scheduler.shutdown();
try {
scheduler.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
//noop
}
}
@Override
public void run() {
for(TemperatureSensor device : w1Mater.getDevices(TemperatureSensor.class)){
if(device.getName().equals(w1Address)){
controller.sendDataReport(new RPiTemperatureSensor(System.currentTimeMillis(), device.getTemperature(TemperatureScale.CELSIUS)));
break;
}
}
}
}

View file

@ -1,48 +1,40 @@
package se.hal.plugin.localsensor;
package se.hal.plugin.raspberry.hardware;
import com.pi4j.io.gpio.*;
import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
import com.pi4j.io.gpio.event.GpioPinListenerDigital;
import zutil.db.DBConnection;
import zutil.log.CompactLogFormatter;
import zutil.log.LogUtil;
import java.sql.SQLException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
public class RPiImpulseCountSensor implements Runnable {
import se.hal.plugin.raspberry.RPiController;
import se.hal.plugin.raspberry.RPiPowerConsumptionSensor;
import se.hal.plugin.raspberry.RPiSensor;
import zutil.log.LogUtil;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
import com.pi4j.io.gpio.event.GpioPinListenerDigital;
public class RPiInteruptPulseFlankCounter implements Runnable, GpioPinListenerDigital, RPiSensor {
private static final int REPORT_TIMEOUT = 60_000; //one minute
private static final Logger logger = LogUtil.getLogger();
private static final int REPORT_TIMEOUT = 60_000; //one minute
private RPiController controller;
private ExecutorService executorPool;
private long nanoSecondsSleep = REPORT_TIMEOUT * 1_000_000L;
private volatile Integer impulseCount = 0;
private ExecutorService executorPool;
private final DBConnection db;
private final int sensorId;
private GpioPinDigitalInput irLightSensor;
public static void main(String args[]) throws Exception {
new RPiImpulseCountSensor(2, RaspiPin.GPIO_02);
}
public RPiInteruptPulseFlankCounter(Pin gpioPin, RPiController controller){
this.controller = controller;
/**
* Constructor
* @param sensorId The ID of this sensor. Will be written to the DB
* @throws Exception
*/
public RPiImpulseCountSensor(int sensorId, Pin pin) throws Exception{
// init logging
CompactLogFormatter formatter = new CompactLogFormatter();
LogUtil.setLevel("se.hal", Level.FINEST);
LogUtil.setFormatter("se.hal", formatter);
LogUtil.setLevel("zutil", Level.FINEST);
LogUtil.setFormatter("zutil", formatter);
LogUtil.setGlobalFormatter(formatter);
this.sensorId = sensorId;
// setup a thread pool for executing jobs
this.executorPool = Executors.newCachedThreadPool();
// create gpio controller
GpioController gpio = null;
@ -57,10 +49,25 @@ public class RPiImpulseCountSensor implements Runnable {
}
// provision gpio pin as an input pin with its internal pull up resistor enabled
final GpioPinDigitalInput irLightSensor = gpio.provisionDigitalInputPin(pin, PinPullResistance.PULL_UP);
irLightSensor = gpio.provisionDigitalInputPin(gpioPin, PinPullResistance.PULL_UP);
// create and register gpio pin listener. May require the program to be run as sudo if the GPIO pin has not been exported
irLightSensor.addListener(new GpioPinListenerDigital() {
irLightSensor.addListener(this);
//start a daemon thread to save the impulse count every minute
Thread thread = new Thread(this);
thread.setDaemon(false);
thread.start();
}
public void close() {
irLightSensor.removeListener(this);
executorPool.shutdown();
}
/**
* GpioPinListenerDigital interface
*/
@Override
public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
if(event.getState() == PinState.LOW){ //low = light went on
@ -72,33 +79,13 @@ public class RPiImpulseCountSensor implements Runnable {
}
}
});
// setup a thread pool for executing database jobs
this.executorPool = Executors.newCachedThreadPool();
// Connect to the database
logger.info("Connecting to db...");
db = new DBConnection(DBConnection.DBMS.SQLite, "hal.db");
//start a daemon thread to save the impulse count every minute
Thread thread = new Thread(this);
thread.setDaemon(false);
thread.start();
}
/**
* This loop will try to save the current time and the number of impulses seen every [IMPULSE_REPORT_TIMEOUT] milliseconds.
* Every iteration the actual loop time will be evaluated and used to calculate the time for the next loop.
*/
@Override
public void run() {
long startTime = System.nanoTime();
synchronized(impulseCount){
impulseCount = 0; //reset the impulse count
}
while(true) {
while(!executorPool.isShutdown()) {
sleepNano(nanoSecondsSleep); //sleep for some time. This variable will be modified every loop to compensate for the loop time spent.
int count = -1;
synchronized(impulseCount){
@ -132,6 +119,7 @@ public class RPiImpulseCountSensor implements Runnable {
/**
* Saves the data to the database.
* This method should block the caller as short time as possible.
* This method should try block the same amount of time every time it is called.
* Try to make the time spent in the method the same for every call (low variation).
*
* @param timestamp_end
@ -142,12 +130,8 @@ public class RPiImpulseCountSensor implements Runnable {
executorPool.execute(new Runnable(){
@Override
public void run() {
logger.log(Level.INFO, "Saving data to DB. timestamp_end="+timestamp_end+", data="+data);
try {
db.exec("INSERT INTO sensor_data_raw(timestamp, sensor_id, data) VALUES("+timestamp_end+", "+RPiImpulseCountSensor.this.sensorId+", "+data+")");
} catch (SQLException e) {
e.printStackTrace();
}
logger.log(Level.INFO, "Reporting data. timestamp_end="+timestamp_end+", data="+data);
controller.sendDataReport(new RPiPowerConsumptionSensor(timestamp_end, data));
}
});
}

View file

@ -0,0 +1,8 @@
{
"version": 1.1,
"name": "Raspberry Pi Sensors",
"interfaces": [
{"se.hal.intf.HalSensorData": "se.hal.plugin.raspberry.RPiPowerConsumptionSensor"},
{"se.hal.intf.HalSensorData": "se.hal.plugin.raspberry.RPiTemperatureSensor"}
]
}

View file

@ -0,0 +1,11 @@
package se.hal.struct;
import se.hal.intf.HalSensorData;
/**
* Created by Ziver on 2015-12-03.
*/
public interface HumiditySensorData extends HalSensorData {
double getHumidity();
}

View file

@ -8,6 +8,4 @@ import se.hal.intf.HalSensorData;
public interface TemperatureSensorData extends HalSensorData {
double getTemperature();
double getHumidity();
}