Commit beeb6072 authored by luz's avatar luz

Hackathon Berlin: Elser Weather Station via RS485 added as static device...

Hackathon Berlin: Elser Weather Station via RS485 added as static device "weatherstation" with config=serial device or forwarder IP
parent 0bc5a89a
//
// Copyright (c) 2013-2015 plan44.ch / Lukas Zeller, Zurich, Switzerland
//
// Author: Lukas Zeller <luz@plan44.ch>
//
// This file is part of vdcd.
//
// vdcd 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 3 of the License, or
// (at your option) any later version.
//
// vdcd 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 vdcd. If not, see <http://www.gnu.org/licenses/>.
//
#include "rs485weather.hpp"
#include "fnv.hpp"
using namespace p44;
WeatherDevice::WeatherDevice(StaticDeviceContainer *aClassContainerP, const string &aDeviceConfig) :
StaticDevice((DeviceClassContainer *)aClassContainerP),
rs485devicename(aDeviceConfig)
{
// assign name for showing on console and for creating dSUID from
// create I/O
// Standard device settings without scene table
primaryGroup = group_black_joker;
installSettings();
// - create temp sensor input
temperatureSensor = SensorBehaviourPtr(new SensorBehaviour(*this));
temperatureSensor->setHardwareSensorConfig(sensorType_temperature, usage_outdoors, -40, 80, 0.1, 3*Second, 5*Minute, 5*Minute);
temperatureSensor->setGroup(group_blue_heating);
temperatureSensor->setHardwareName("Outdoor Temperature -40..80 °C");
addBehaviour(temperatureSensor);
// - create sun sensor input
sun1Sensor = SensorBehaviourPtr(new SensorBehaviour(*this));
sun1Sensor->setHardwareSensorConfig(sensorType_illumination, usage_outdoors, 0, 99000, 1000, 3*Second, 5*Minute, 5*Minute);
sun1Sensor->setGroup(group_yellow_light);
sun1Sensor->setHardwareName("sunlight in lux");
addBehaviour(sun1Sensor);
// - create twilight binary input
twilightInput = BinaryInputBehaviourPtr(new BinaryInputBehaviour(*this));
twilightInput->setGroup(group_yellow_light);
twilightInput->setHardwareInputConfig(binInpType_twilight, usage_outdoors, true, Never);
twilightInput->setHardwareName("Twilight indicator");
addBehaviour(twilightInput);
// - create sun sensor input
daylightSensor = SensorBehaviourPtr(new SensorBehaviour(*this));
daylightSensor->setHardwareSensorConfig(sensorType_illumination, usage_outdoors, 0, 99000, 100, 3*Second, 5*Minute, 5*Minute);
daylightSensor->setGroup(group_yellow_light);
daylightSensor->setHardwareName("daylight in lux");
addBehaviour(daylightSensor);
// - create sun sensor input
windSensor = SensorBehaviourPtr(new SensorBehaviour(*this));
windSensor->setHardwareSensorConfig(sensorType_wind_speed, usage_outdoors, 0, 70, 4, 3*Second, 5*Minute, 5*Minute);
windSensor->setGroup(group_blue_heating);
windSensor->setHardwareName("wind in m/s");
addBehaviour(windSensor);
// - create rain binary input
rainInput = BinaryInputBehaviourPtr(new BinaryInputBehaviour(*this));
rainInput->setGroup(group_yellow_light);
rainInput->setHardwareInputConfig(binInpType_rain, usage_outdoors, true, Never);
rainInput->setHardwareName("rain");
addBehaviour(rainInput);
// done, calculate dSUID
deriveDsUid();
}
string WeatherDevice::modelName()
{
return "Elsner P03";
}
void WeatherDevice::initializeDevice(StatusCB aCompletedCB, bool aFactoryReset)
{
serial = SerialCommPtr(new SerialComm(MainLoop::currentMainLoop()));
serial->setConnectionParameters(rs485devicename.c_str(), 2101, 19200);
serial->setReceiveHandler(boost::bind(&WeatherDevice::serialReceiveHandler, this, _1));
serial->establishConnection();
telegramIndex = -1;
// done
if (aCompletedCB) aCompletedCB(ErrorPtr());
}
void WeatherDevice::serialReceiveHandler(ErrorPtr aError)
{
if (Error::isOK(aError)) {
size_t n = serial->numBytesReady();
if (n>0) {
uint8_t byte;
serial->receiveBytes(1, &byte, aError);
if (Error::isOK(aError)) {
if (telegramIndex<0) {
// wait for start of telegram
if (byte=='W') {
telegramIndex = 0;
}
}
if (telegramIndex>=0 && telegramIndex<numTelegramBytes) {
telegram[telegramIndex++] = byte;
if (telegramIndex>=numTelegramBytes) {
// evaluate
// TODO: checksum
// - temperature
double temp =
(telegram[2]-'0')*10 +
(telegram[3]-'0')*1 +
(telegram[5]-'0')*0.1;
temperatureSensor->updateSensorValue(temp);
// - sun
double sun =
(telegram[6]-'0')*10000 +
(telegram[7]-'0')*1000;
sun1Sensor->updateSensorValue(sun);
// - twilight
bool isTwilight = telegram[12]=='J';
twilightInput->updateInputState(isTwilight);
// - daylight
double daylight =
(telegram[13]-'0')*10000 +
(telegram[14]-'0')*1000 +
(telegram[15]-'0')*100;
daylightSensor->updateSensorValue(daylight);
// - wind
double wind =
(telegram[16]-'0')*10 +
(telegram[17]-'0')*1 +
(telegram[19]-'0')*0.1;
windSensor->updateSensorValue(wind);
// - rain
bool rain = telegram[20]=='J';
rainInput->updateInputState(rain);
// reset index
telegramIndex = 0;
}
}
}
}
}
}
void WeatherDevice::deriveDsUid()
{
// vDC implementation specific UUID:
// UUIDv5 with name = classcontainerinstanceid::consoledevicename
DsUid vdcNamespace(DSUID_P44VDC_NAMESPACE_UUID);
string s = classContainerP->deviceClassContainerInstanceIdentifier();
s += "::" + rs485devicename;
dSUID.setNameInSpace(s, vdcNamespace);
}
string WeatherDevice::description()
{
string s = inherited::description();
string_format_append(s, "- drives a Elsner RS485 weather station\n");
return s;
}
//
// Copyright (c) 2013-2015 plan44.ch / Lukas Zeller, Zurich, Switzerland
//
// Author: Lukas Zeller <luz@plan44.ch>
//
// This file is part of vdcd.
//
// vdcd 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 3 of the License, or
// (at your option) any later version.
//
// vdcd 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 vdcd. If not, see <http://www.gnu.org/licenses/>.
//
#ifndef __vdcd__rs485weather__
#define __vdcd__rs485weather__
#include "device.hpp"
#include "staticdevicecontainer.hpp"
#include "serialcomm.hpp"
#include "sensorbehaviour.hpp"
#include "binaryinputbehaviour.hpp"
using namespace std;
namespace p44 {
class StaticDeviceContainer;
class WeatherDevice;
typedef boost::intrusive_ptr<WeatherDevice> WeatherDevicePtr;
class WeatherDevice : public StaticDevice
{
typedef StaticDevice inherited;
string rs485devicename;
SerialCommPtr serial;
int telegramIndex;
int checksum;
static const size_t numTelegramBytes = 40;
uint8_t telegram[numTelegramBytes];
SensorBehaviourPtr temperatureSensor;
SensorBehaviourPtr sun1Sensor;
// SensorBehaviourPtr sun2Sensor;
// SensorBehaviourPtr sun3Sensor;
BinaryInputBehaviourPtr twilightInput;
SensorBehaviourPtr daylightSensor;
SensorBehaviourPtr windSensor;
BinaryInputBehaviourPtr rainInput;
public:
WeatherDevice(StaticDeviceContainer *aClassContainerP, const string &aDeviceConfig);
/// device type identifier
/// @return constant identifier for this type of device (one container might contain more than one type)
virtual const char *deviceTypeIdentifier() { return "weatherstation"; };
/// description of object, mainly for debug and logging
/// @return textual description of object
virtual string description();
void initializeDevice(StatusCB aCompletedCB, bool aFactoryReset);
/// @name identification of the addressable entity
/// @{
/// @return human readable model name/short description
virtual string modelName();
/// @return Vendor ID in URN format to identify vendor as uniquely as possible
virtual string vendorId() { return "vendorname:plan44.ch"; };
/// @}
protected:
void deriveDsUid();
private:
// void binaryInputHandler(bool aState, MLMicroSeconds aTimeStamp);
// void sensorValueHandler(double aValue, MLMicroSeconds aTimeStamp);
void serialReceiveHandler(ErrorPtr aError);
};
} // namespace p44
#endif /* defined(__vdcd__rs485weather__) */
......@@ -25,6 +25,7 @@
#include "analogiodevice.hpp"
#include "consoledevice.hpp"
#include "sparkiodevice.hpp"
#include "rs485weather.hpp"
using namespace p44;
......@@ -134,6 +135,10 @@ StaticDevicePtr StaticDeviceContainer::addStaticDevice(string aDeviceType, strin
// spark core based device
newDev = DevicePtr(new SparkIoDevice(this, aDeviceConfig));
}
else if (aDeviceType=="weatherstation") {
// spark core based device
newDev = DevicePtr(new WeatherDevice(this, aDeviceConfig));
}
// add to container if device was created
if (newDev) {
// add to container
......
......@@ -37,7 +37,6 @@
ED31269A18318CC100FAF28B /* p44obj.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED81337717C6C765003982CC /* p44obj.cpp */; };
ED31269C18318CC100FAF28B /* macaddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EDDE42BC17F35419005B97A0 /* macaddress.cpp */; };
ED31269D18318CC100FAF28B /* dsscene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED81337117C644AE003982CC /* dsscene.cpp */; };
ED31269E18318CC100FAF28B /* demodevicecontainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED312692183186C200FAF28B /* demodevicecontainer.cpp */; };
ED3126A018318CC100FAF28B /* logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED6D7BEE1716EAA6005DED18 /* logger.cpp */; };
ED3126A218318CC100FAF28B /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED026CF7171D9CAB00AD5FD6 /* utils.cpp */; };
ED3126A318318CC100FAF28B /* devicecontainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED026CFA171E8D6200AD5FD6 /* devicecontainer.cpp */; };
......@@ -124,6 +123,8 @@
ED76273019210FBB0068D9A3 /* colorlightbehaviour.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED7627241920E8F70068D9A3 /* colorlightbehaviour.cpp */; };
ED780C731A17CA6600DC3F60 /* movinglightbehaviour.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED780C721A17CA6600DC3F60 /* movinglightbehaviour.cpp */; };
ED780C741A17CA6600DC3F60 /* movinglightbehaviour.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED780C721A17CA6600DC3F60 /* movinglightbehaviour.cpp */; };
ED8038111B18645A0054E4B0 /* rs485weather.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED80380F1B18645A0054E4B0 /* rs485weather.cpp */; };
ED8038121B18817D0054E4B0 /* demodevicecontainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED312692183186C200FAF28B /* demodevicecontainer.cpp */; };
ED81337317C644AE003982CC /* dsscene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED81337117C644AE003982CC /* dsscene.cpp */; };
ED81337617C65F7E003982CC /* devicesettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED81337417C65F7E003982CC /* devicesettings.cpp */; };
ED81337917C6C765003982CC /* p44obj.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED81337717C6C765003982CC /* p44obj.cpp */; };
......@@ -367,6 +368,8 @@
ED7627241920E8F70068D9A3 /* colorlightbehaviour.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = colorlightbehaviour.cpp; sourceTree = "<group>"; };
ED780C711A17CA6600DC3F60 /* movinglightbehaviour.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = movinglightbehaviour.hpp; sourceTree = "<group>"; };
ED780C721A17CA6600DC3F60 /* movinglightbehaviour.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = movinglightbehaviour.cpp; sourceTree = "<group>"; };
ED80380F1B18645A0054E4B0 /* rs485weather.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rs485weather.cpp; sourceTree = "<group>"; };
ED8038101B18645A0054E4B0 /* rs485weather.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = rs485weather.hpp; sourceTree = "<group>"; };
ED81337117C644AE003982CC /* dsscene.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = dsscene.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
ED81337217C644AE003982CC /* dsscene.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = dsscene.hpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
ED81337417C65F7E003982CC /* devicesettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = devicesettings.cpp; sourceTree = "<group>"; };
......@@ -652,6 +655,8 @@
ED5D487D19ED701E000DF5A5 /* analogiodevice.hpp */,
EDCF05C3188D764E00B47526 /* sparkiodevice.cpp */,
EDCF05C4188D764E00B47526 /* sparkiodevice.hpp */,
ED80380F1B18645A0054E4B0 /* rs485weather.cpp */,
ED8038101B18645A0054E4B0 /* rs485weather.hpp */,
);
path = simpleio;
sourceTree = "<group>";
......@@ -974,11 +979,11 @@
EDF62B49183A0ED20016BFDA /* upnpdevicecontainer.cpp in Sources */,
ED31269D18318CC100FAF28B /* dsscene.cpp in Sources */,
ED5133BE19F6A6B70027999E /* simplescene.cpp in Sources */,
ED31269E18318CC100FAF28B /* demodevicecontainer.cpp in Sources */,
ED3126A018318CC100FAF28B /* logger.cpp in Sources */,
ED3126A218318CC100FAF28B /* utils.cpp in Sources */,
ED3126A318318CC100FAF28B /* devicecontainer.cpp in Sources */,
ED3126A618318CC100FAF28B /* deviceclasscontainer.cpp in Sources */,
ED8038121B18817D0054E4B0 /* demodevicecontainer.cpp in Sources */,
ED3126A818318CC100FAF28B /* fdcomm.cpp in Sources */,
ED3126A918318CC100FAF28B /* outputbehaviour.cpp in Sources */,
ED3126AA18318CC100FAF28B /* propertycontainer.cpp in Sources */,
......@@ -1118,6 +1123,7 @@
EDB4062317D4D9B5003783CE /* huedevice.cpp in Sources */,
EDDDD5521A125FBC007D2ABE /* oladevice.cpp in Sources */,
EDB1893117D4B7330088B6A5 /* ssdpsearch.cpp in Sources */,
ED8038111B18645A0054E4B0 /* rs485weather.cpp in Sources */,
ED6FCC7D17CB493400267E43 /* enoceanrps.cpp in Sources */,
ED5D486819ED502F000DF5A5 /* analogio.cpp in Sources */,
ED55760D174CC03B00CCC4DD /* socketcomm.cpp in Sources */,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment