773 lines
25 KiB
C++
773 lines
25 KiB
C++
//
|
|
// Copyright (C) 2012 Telldus Technologies AB. All rights reserved.
|
|
//
|
|
// Copyright: See COPYING file that comes with this distribution
|
|
//
|
|
//
|
|
#include "service/DeviceManager.h"
|
|
#include <time.h>
|
|
#include <list>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#include "service/ControllerMessage.h"
|
|
#include "common/Mutex.h"
|
|
#include "service/Sensor.h"
|
|
#include "service/Settings.h"
|
|
#include "common/Strings.h"
|
|
#include "common/Message.h"
|
|
#include "service/Log.h"
|
|
|
|
typedef std::map<int, Device *> DeviceMap;
|
|
|
|
class DeviceManager::PrivateData {
|
|
public:
|
|
DeviceMap devices;
|
|
std::list<Sensor *> sensorList;
|
|
Settings set;
|
|
TelldusCore::Mutex lock;
|
|
ControllerManager *controllerManager;
|
|
TelldusCore::EventRef deviceUpdateEvent;
|
|
};
|
|
|
|
DeviceManager::DeviceManager(ControllerManager *controllerManager, TelldusCore::EventRef deviceUpdateEvent) {
|
|
d = new PrivateData;
|
|
d->controllerManager = controllerManager;
|
|
d->deviceUpdateEvent = deviceUpdateEvent;
|
|
fillDevices();
|
|
}
|
|
|
|
DeviceManager::~DeviceManager(void) {
|
|
{
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
for (DeviceMap::iterator it = d->devices.begin(); it != d->devices.end(); ++it) {
|
|
{TelldusCore::MutexLocker deviceLocker(it->second);} // aquire lock, and release it, just to see that the device it's not in use anywhere
|
|
delete(it->second);
|
|
}
|
|
for (std::list<Sensor *>::iterator it = d->sensorList.begin(); it != d->sensorList.end(); ++it) {
|
|
{TelldusCore::MutexLocker sensorLocker(*it);} // aquire lock, and release it, just to see that the device it's not in use anywhere
|
|
delete(*it);
|
|
}
|
|
}
|
|
delete d;
|
|
}
|
|
|
|
void DeviceManager::fillDevices() {
|
|
int numberOfDevices = d->set.getNumberOfNodes(Settings::Device);
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
|
|
for (int i = 0; i < numberOfDevices; ++i) {
|
|
int id = d->set.getNodeId(Settings::Device, i);
|
|
d->devices[id] = new Device(id);
|
|
d->devices[id]->setName(d->set.getName(Settings::Device, id));
|
|
d->devices[id]->setModel(d->set.getModel(id));
|
|
d->devices[id]->setProtocolName(d->set.getProtocol(id));
|
|
d->devices[id]->setPreferredControllerId(d->set.getPreferredControllerId(id));
|
|
d->devices[id]->setLastSentCommand(d->set.getDeviceState(id), d->set.getDeviceStateValue(id));
|
|
d->devices[id]->setParameter(L"house", d->set.getDeviceParameter(id, L"house"));
|
|
d->devices[id]->setParameter(L"unit", d->set.getDeviceParameter(id, L"unit"));
|
|
d->devices[id]->setParameter(L"code", d->set.getDeviceParameter(id, L"code"));
|
|
d->devices[id]->setParameter(L"units", d->set.getDeviceParameter(id, L"units"));
|
|
d->devices[id]->setParameter(L"fade", d->set.getDeviceParameter(id, L"fade"));
|
|
d->devices[id]->setParameter(L"system", d->set.getDeviceParameter(id, L"system"));
|
|
d->devices[id]->setParameter(L"devices", d->set.getDeviceParameter(id, L"devices"));
|
|
}
|
|
}
|
|
|
|
int DeviceManager::getDeviceLastSentCommand(int deviceId, int methodsSupported) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
return it->second->getLastSentCommand(methodsSupported);
|
|
}
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
int DeviceManager::setDeviceLastSentCommand(int deviceId, int command, const std::wstring &value) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
d->set.setDeviceState(deviceId, command, value);
|
|
it->second->setLastSentCommand(command, value);
|
|
}
|
|
else {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
return TELLSTICK_SUCCESS;
|
|
}
|
|
|
|
std::wstring DeviceManager::getDeviceStateValue(int deviceId) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return L"UNKNOWN";
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
return it->second->getStateValue();
|
|
}
|
|
return L"UNKNOWN";
|
|
}
|
|
|
|
int DeviceManager::getDeviceMethods(int deviceId, int methodsSupported) {
|
|
return Device::maskUnsupportedMethods(DeviceManager::getDeviceMethods(deviceId), methodsSupported);
|
|
}
|
|
|
|
int DeviceManager::getDeviceMethods(int deviceId) {
|
|
std::set<int> duplicateDeviceIds;
|
|
return DeviceManager::getDeviceMethods(deviceId, duplicateDeviceIds);
|
|
}
|
|
|
|
int DeviceManager::getDeviceMethods(int deviceId, std::set<int> &duplicateDeviceIds) {
|
|
int type = 0;
|
|
int methods = 0;
|
|
std::wstring deviceIds;
|
|
std::wstring protocol;
|
|
|
|
{
|
|
// devices locked
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
{
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
type = it->second->getType();
|
|
methods = it->second->getMethods();
|
|
deviceIds = it->second->getParameter(L"devices");
|
|
protocol = it->second->getProtocolName();
|
|
}
|
|
}
|
|
}
|
|
if(type == 0) {
|
|
return 0;
|
|
}
|
|
if(type == TELLSTICK_TYPE_GROUP) {
|
|
// get all methods that some device in the groups supports
|
|
std::wstring deviceIdBuffer;
|
|
std::wstringstream devicesstream(deviceIds);
|
|
methods = 0;
|
|
|
|
duplicateDeviceIds.insert(deviceId);
|
|
|
|
while(std::getline(devicesstream, deviceIdBuffer, L',')) {
|
|
int deviceIdInGroup = TelldusCore::wideToInteger(deviceIdBuffer);
|
|
if(duplicateDeviceIds.count(deviceIdInGroup) == 1) {
|
|
// action for device already executed, or will execute, do nothing to avoid infinite loop
|
|
continue;
|
|
}
|
|
|
|
duplicateDeviceIds.insert(deviceIdInGroup);
|
|
|
|
int deviceMethods = getDeviceMethods(deviceIdInGroup, duplicateDeviceIds);
|
|
if(deviceMethods > 0) {
|
|
methods |= deviceMethods;
|
|
}
|
|
}
|
|
}
|
|
return methods;
|
|
}
|
|
|
|
std::wstring DeviceManager::getDeviceModel(int deviceId) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return L"UNKNOWN";
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
return it->second->getModel();
|
|
}
|
|
return L"UNKNOWN";
|
|
}
|
|
|
|
int DeviceManager::setDeviceModel(int deviceId, const std::wstring &model) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
int ret = d->set.setModel(deviceId, model);
|
|
if (ret != TELLSTICK_SUCCESS) {
|
|
return ret;
|
|
}
|
|
it->second->setModel(model);
|
|
}
|
|
else {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
return TELLSTICK_SUCCESS;
|
|
}
|
|
|
|
std::wstring DeviceManager::getDeviceName(int deviceId) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return L"UNKNOWN";
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
return it->second->getName();
|
|
}
|
|
return L"UNKNOWN";
|
|
}
|
|
|
|
int DeviceManager::setDeviceName(int deviceId, const std::wstring &name) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
int ret = d->set.setName(Settings::Device, deviceId, name);
|
|
if (ret != TELLSTICK_SUCCESS) {
|
|
return ret;
|
|
}
|
|
it->second->setName(name);
|
|
}
|
|
else {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
return TELLSTICK_SUCCESS;
|
|
}
|
|
|
|
std::wstring DeviceManager::getDeviceParameter(int deviceId, const std::wstring &name, const std::wstring &defaultValue) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return defaultValue;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
std::wstring returnString = it->second->getParameter(name);
|
|
if(returnString != L"") {
|
|
return returnString;
|
|
}
|
|
}
|
|
return defaultValue;
|
|
}
|
|
|
|
int DeviceManager::setDeviceParameter(int deviceId, const std::wstring &name, const std::wstring &value) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
int ret = d->set.setDeviceParameter(deviceId, name, value);
|
|
if (ret != TELLSTICK_SUCCESS) {
|
|
return ret;
|
|
}
|
|
it->second->setParameter(name, value);
|
|
}
|
|
else {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
return TELLSTICK_SUCCESS;
|
|
}
|
|
|
|
std::wstring DeviceManager::getDeviceProtocol(int deviceId) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return L"UNKNOWN";
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
return it->second->getProtocolName();
|
|
}
|
|
return L"UNKNOWN";
|
|
}
|
|
|
|
int DeviceManager::setDeviceProtocol(int deviceId, const std::wstring &protocol) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
int ret = d->set.setProtocol(deviceId, protocol);
|
|
if (ret != TELLSTICK_SUCCESS) {
|
|
return ret;
|
|
}
|
|
it->second->setProtocolName(protocol);
|
|
}
|
|
else {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
return TELLSTICK_SUCCESS;
|
|
}
|
|
|
|
int DeviceManager::getNumberOfDevices() {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
return (int)d->devices.size();
|
|
}
|
|
|
|
int DeviceManager::addDevice() {
|
|
int id = d->set.addNode(Settings::Device);
|
|
if(id < 0) {
|
|
return id;
|
|
}
|
|
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
d->devices[id] = new Device(id);
|
|
if(!d->devices[id]) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
return id;
|
|
}
|
|
|
|
int DeviceManager::getDeviceId(int deviceIndex) {
|
|
return d->set.getNodeId(Settings::Device, deviceIndex);
|
|
}
|
|
|
|
int DeviceManager::getDeviceType(int deviceId) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
return it->second->getType();
|
|
}
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
int DeviceManager::getPreferredControllerId(int deviceId) {
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
return it->second->getPreferredControllerId();
|
|
}
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
void DeviceManager::connectTellStickController(int vid, int pid, const std::string &serial) {
|
|
d->controllerManager->deviceInsertedOrRemoved(vid, pid, serial, true);
|
|
}
|
|
|
|
void DeviceManager::disconnectTellStickController(int vid, int pid, const std::string &serial) {
|
|
d->controllerManager->deviceInsertedOrRemoved(vid, pid, serial, false);
|
|
}
|
|
|
|
int DeviceManager::doAction(int deviceId, int action, unsigned char data) {
|
|
Device *device = 0;
|
|
// On the stack and will be released if we have a device lock.
|
|
std::auto_ptr<TelldusCore::MutexLocker> deviceLocker(0);
|
|
{
|
|
// devicelist locked
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it == d->devices.end()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND; // not found
|
|
}
|
|
// device locked
|
|
deviceLocker = std::auto_ptr<TelldusCore::MutexLocker>(new TelldusCore::MutexLocker(it->second));
|
|
device = it->second;
|
|
} // devicelist unlocked
|
|
|
|
int retval = TELLSTICK_ERROR_UNKNOWN;
|
|
|
|
if(device->getType() == TELLSTICK_TYPE_GROUP || device->getType() == TELLSTICK_TYPE_SCENE) {
|
|
std::wstring devices = device->getParameter(L"devices");
|
|
deviceLocker = std::auto_ptr<TelldusCore::MutexLocker>(0);
|
|
std::set<int> *duplicateDeviceIds = new std::set<int>;
|
|
retval = doGroupAction(devices, action, data, device->getType(), deviceId, duplicateDeviceIds);
|
|
delete duplicateDeviceIds;
|
|
|
|
{
|
|
// reaquire device lock, make sure it still exists
|
|
// devicelist locked
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it == d->devices.end()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND; // not found
|
|
}
|
|
// device locked
|
|
deviceLocker = std::auto_ptr<TelldusCore::MutexLocker>(new TelldusCore::MutexLocker(it->second));
|
|
device = it->second;
|
|
} // devicelist unlocked
|
|
}
|
|
else {
|
|
Controller *controller = d->controllerManager->getBestControllerById(device->getPreferredControllerId());
|
|
if(!controller) {
|
|
Log::warning("Trying to execute action, but no controller found. Rescanning USB ports");
|
|
// no controller found, scan for one, and retry once
|
|
d->controllerManager->loadControllers();
|
|
controller = d->controllerManager->getBestControllerById(device->getPreferredControllerId());
|
|
}
|
|
|
|
if(controller) {
|
|
retval = device->doAction(action, data, controller);
|
|
if(retval == TELLSTICK_ERROR_BROKEN_PIPE) {
|
|
Log::warning("Error in communication with TellStick when executing action. Resetting USB");
|
|
d->controllerManager->resetController(controller);
|
|
}
|
|
if(retval == TELLSTICK_ERROR_BROKEN_PIPE || retval == TELLSTICK_ERROR_NOT_FOUND) {
|
|
Log::warning("Rescanning USB ports");
|
|
d->controllerManager->loadControllers();
|
|
controller = d->controllerManager->getBestControllerById(device->getPreferredControllerId());
|
|
if(!controller) {
|
|
Log::error("No contoller (TellStick) found, even after reset. Giving up.");
|
|
return TELLSTICK_ERROR_NOT_FOUND;
|
|
}
|
|
retval = device->doAction(action, data, controller); // retry one more time
|
|
}
|
|
} else {
|
|
Log::error("No contoller (TellStick) found after one retry. Giving up.");
|
|
return TELLSTICK_ERROR_NOT_FOUND;
|
|
}
|
|
}
|
|
if(retval == TELLSTICK_SUCCESS && device->getType() != TELLSTICK_TYPE_SCENE && device->getMethods() & action) {
|
|
// if method isn't explicitly supported by device, but used anyway as a fallback (i.e. bell), don't change state
|
|
std::wstring datastring = TelldusCore::charUnsignedToWstring(data);
|
|
if (this->triggerDeviceStateChange(deviceId, action, datastring)) {
|
|
device->setLastSentCommand(action, datastring);
|
|
d->set.setDeviceState(deviceId, action, datastring);
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
int DeviceManager::doGroupAction(const std::wstring devices, const int action, const unsigned char data, const int type, const int groupDeviceId, std::set<int> *duplicateDeviceIds) {
|
|
int retval = TELLSTICK_ERROR_METHOD_NOT_SUPPORTED;
|
|
std::wstring singledevice;
|
|
std::wstringstream devicesstream(devices);
|
|
|
|
duplicateDeviceIds->insert(groupDeviceId);
|
|
|
|
while(std::getline(devicesstream, singledevice, L',')) {
|
|
int deviceId = TelldusCore::wideToInteger(singledevice);
|
|
|
|
if(duplicateDeviceIds->count(deviceId) == 1) {
|
|
// action for device already executed, or will execute, do nothing to avoid infinite loop
|
|
continue;
|
|
}
|
|
|
|
duplicateDeviceIds->insert(deviceId);
|
|
|
|
int deviceReturnValue = TELLSTICK_SUCCESS;
|
|
|
|
if(type == TELLSTICK_TYPE_SCENE && (action == TELLSTICK_TURNON || action == TELLSTICK_EXECUTE)) {
|
|
deviceReturnValue = executeScene(singledevice, groupDeviceId);
|
|
}
|
|
else if(type == TELLSTICK_TYPE_GROUP) {
|
|
if(deviceId != 0) {
|
|
int childType = DeviceManager::getDeviceType(deviceId);
|
|
if(childType == TELLSTICK_TYPE_DEVICE) {
|
|
deviceReturnValue = doAction(deviceId, action, data);
|
|
}
|
|
else if(childType == TELLSTICK_TYPE_SCENE) {
|
|
deviceReturnValue = doGroupAction(DeviceManager::getDeviceParameter(deviceId, L"devices", L""), action, data, childType, deviceId, duplicateDeviceIds); // TODO make scenes infinite loops-safe
|
|
}
|
|
else {
|
|
// group (in group)
|
|
deviceReturnValue = doGroupAction(DeviceManager::getDeviceParameter(deviceId, L"devices", L""), action, data, childType, deviceId, duplicateDeviceIds);
|
|
|
|
if(deviceReturnValue == TELLSTICK_SUCCESS) {
|
|
std::wstring datastring = TelldusCore::charUnsignedToWstring(data);
|
|
if (this->triggerDeviceStateChange(deviceId, action, datastring)) {
|
|
DeviceManager::setDeviceLastSentCommand(deviceId, action, datastring);
|
|
d->set.setDeviceState(deviceId, action, datastring);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
deviceReturnValue = TELLSTICK_ERROR_DEVICE_NOT_FOUND; // Probably incorrectly formatted parameter
|
|
}
|
|
}
|
|
|
|
if(deviceReturnValue != TELLSTICK_ERROR_METHOD_NOT_SUPPORTED) {
|
|
// if error(s), return the last error, but still try to continue the action with the other devices
|
|
// if the error is a method not supported we igore is since there might be others supporting it
|
|
// If no devices support the method the default value will be returned (method not supported)
|
|
retval = deviceReturnValue;
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
int DeviceManager::executeScene(std::wstring singledevice, int groupDeviceId) {
|
|
std::wstringstream devicestream(singledevice);
|
|
|
|
const int deviceParameterLength = 3;
|
|
std::wstring deviceParts[deviceParameterLength] = {L"", L"", L""};
|
|
std::wstring devicePart = L"";
|
|
int i = 0;
|
|
while(std::getline(devicestream, devicePart, L':') && i < deviceParameterLength) {
|
|
deviceParts[i] = devicePart;
|
|
i++;
|
|
}
|
|
|
|
if(deviceParts[0] == L"" || deviceParts[1] == L"") {
|
|
return TELLSTICK_ERROR_UNKNOWN; // malformed or missing parameter
|
|
}
|
|
|
|
int deviceId = TelldusCore::wideToInteger(deviceParts[0]);
|
|
if(deviceId == groupDeviceId) {
|
|
return TELLSTICK_ERROR_UNKNOWN; // the scene itself has been added to its devices, avoid infinite loop
|
|
}
|
|
int method = Device::methodId(TelldusCore::wideToString(deviceParts[1])); // support methodparts both in the form of integers (e.g. TELLSTICK_TURNON) or text (e.g. "turnon")
|
|
if(method == 0) {
|
|
method = TelldusCore::wideToInteger(deviceParts[1]);
|
|
}
|
|
unsigned char devicedata = 0;
|
|
if(deviceParts[2] != L"") {
|
|
devicedata = TelldusCore::wideToInteger(deviceParts[2]);
|
|
}
|
|
|
|
if(deviceId > 0 && method > 0) { // check for format error in parameter "devices"
|
|
return doAction(deviceId, method, devicedata);
|
|
}
|
|
|
|
return TELLSTICK_ERROR_UNKNOWN;
|
|
}
|
|
|
|
int DeviceManager::removeDevice(int deviceId) {
|
|
Device *device = 0;
|
|
{
|
|
int ret = d->set.removeNode(Settings::Device, deviceId); // remove from register/settings
|
|
if (ret != TELLSTICK_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
if (!d->devices.size()) {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
DeviceMap::iterator it = d->devices.find(deviceId);
|
|
if (it != d->devices.end()) {
|
|
device = it->second;
|
|
d->devices.erase(it); // remove from list, keep reference
|
|
}
|
|
else {
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
}
|
|
{TelldusCore::MutexLocker lock(device);} // waiting for device lock, if it's aquired, just unlock again. Device is removed from list, and cannot be accessed from anywhere else
|
|
delete device;
|
|
|
|
return TELLSTICK_SUCCESS;
|
|
}
|
|
|
|
std::wstring DeviceManager::getSensors() const {
|
|
TelldusCore::MutexLocker sensorListLocker(&d->lock);
|
|
|
|
TelldusCore::Message msg;
|
|
|
|
msg.addArgument((int)d->sensorList.size());
|
|
|
|
for (std::list<Sensor *>::iterator it = d->sensorList.begin(); it != d->sensorList.end(); ++it) {
|
|
TelldusCore::MutexLocker sensorLocker(*it);
|
|
msg.addArgument((*it)->protocol());
|
|
msg.addArgument((*it)->model());
|
|
msg.addArgument((*it)->id());
|
|
msg.addArgument((*it)->dataTypes());
|
|
}
|
|
|
|
return msg;
|
|
}
|
|
|
|
std::wstring DeviceManager::getSensorValue(const std::wstring &protocol, const std::wstring &model, int id, int dataType) const {
|
|
TelldusCore::MutexLocker sensorListLocker(&d->lock);
|
|
Sensor *sensor = 0;
|
|
for (std::list<Sensor *>::iterator it = d->sensorList.begin(); it != d->sensorList.end(); ++it) {
|
|
TelldusCore::MutexLocker sensorLocker(*it);
|
|
if (!TelldusCore::comparei((*it)->protocol(), protocol)) {
|
|
continue;
|
|
}
|
|
if (!TelldusCore::comparei((*it)->model(), model)) {
|
|
continue;
|
|
}
|
|
if ((*it)->id() != id) {
|
|
continue;
|
|
}
|
|
sensor = *it;
|
|
break;
|
|
}
|
|
|
|
if (!sensor) {
|
|
return L"";
|
|
}
|
|
TelldusCore::MutexLocker sensorLocker(sensor);
|
|
TelldusCore::Message msg;
|
|
std::string value = sensor->value(dataType);
|
|
if (value.length() > 0) {
|
|
msg.addArgument(TelldusCore::charToWstring(value.c_str()));
|
|
msg.addArgument((int)sensor->timestamp());
|
|
}
|
|
return msg;
|
|
}
|
|
|
|
|
|
void DeviceManager::handleControllerMessage(const ControllerEventData &eventData) {
|
|
// Trigger raw-event
|
|
EventUpdateData *eventUpdateData = new EventUpdateData();
|
|
eventUpdateData->messageType = L"TDRawDeviceEvent";
|
|
eventUpdateData->controllerId = eventData.controllerId;
|
|
eventUpdateData->eventValue = TelldusCore::charToWstring(eventData.msg.c_str());
|
|
d->deviceUpdateEvent->signal(eventUpdateData);
|
|
|
|
ControllerMessage msg(eventData.msg);
|
|
if (msg.msgClass().compare("sensor") == 0) {
|
|
handleSensorMessage(msg);
|
|
return;
|
|
}
|
|
|
|
TelldusCore::MutexLocker deviceListLocker(&d->lock);
|
|
for (DeviceMap::iterator it = d->devices.begin(); it != d->devices.end(); ++it) {
|
|
TelldusCore::MutexLocker deviceLocker(it->second);
|
|
if (!TelldusCore::comparei(it->second->getProtocolName(), msg.protocol())) {
|
|
continue;
|
|
}
|
|
if (! (it->second->getMethods() & msg.method())) {
|
|
continue;
|
|
}
|
|
|
|
std::list<std::string> parameters = it->second->getParametersForProtocol();
|
|
bool thisDevice = true;
|
|
for (std::list<std::string>::iterator paramIt = parameters.begin(); paramIt != parameters.end(); ++paramIt) {
|
|
if(!TelldusCore::comparei(it->second->getParameter(TelldusCore::charToWstring((*paramIt).c_str())), TelldusCore::charToWstring(msg.getParameter(*paramIt).c_str()))) {
|
|
thisDevice = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!thisDevice) {
|
|
continue;
|
|
}
|
|
|
|
if (this->triggerDeviceStateChange(it->first, msg.method(), L"")) {
|
|
d->set.setDeviceState(it->first, msg.method(), L"");
|
|
it->second->setLastSentCommand(msg.method(), L"");
|
|
}
|
|
}
|
|
}
|
|
|
|
void DeviceManager::handleSensorMessage(const ControllerMessage &msg) {
|
|
TelldusCore::MutexLocker sensorListLocker(&d->lock);
|
|
Sensor *sensor = 0;
|
|
for (std::list<Sensor *>::iterator it = d->sensorList.begin(); it != d->sensorList.end(); ++it) {
|
|
TelldusCore::MutexLocker sensorLocker(*it);
|
|
if (!TelldusCore::comparei((*it)->protocol(), msg.protocol())) {
|
|
continue;
|
|
}
|
|
if (!TelldusCore::comparei((*it)->model(), msg.model())) {
|
|
continue;
|
|
}
|
|
if ((*it)->id() != msg.getIntParameter("id")) {
|
|
continue;
|
|
}
|
|
sensor = *it;
|
|
break;
|
|
}
|
|
|
|
if (!sensor) {
|
|
sensor = new Sensor(msg.protocol(), msg.model(), msg.getIntParameter("id"));
|
|
d->sensorList.push_back(sensor);
|
|
}
|
|
TelldusCore::MutexLocker sensorLocker(sensor);
|
|
|
|
time_t t = time(NULL);
|
|
|
|
setSensorValueAndSignal("temp", TELLSTICK_TEMPERATURE, sensor, msg, t);
|
|
setSensorValueAndSignal("humidity", TELLSTICK_HUMIDITY, sensor, msg, t);
|
|
}
|
|
|
|
void DeviceManager::setSensorValueAndSignal( const std::string &dataType, int dataTypeId, Sensor *sensor, const ControllerMessage &msg, time_t timestamp) const {
|
|
if (!msg.hasParameter(dataType)) {
|
|
return;
|
|
}
|
|
sensor->setValue(dataTypeId, msg.getParameter(dataType), timestamp);
|
|
|
|
EventUpdateData *eventData = new EventUpdateData();
|
|
eventData->messageType = L"TDSensorEvent";
|
|
eventData->protocol = sensor->protocol();
|
|
eventData->model = sensor->model();
|
|
eventData->sensorId = sensor->id();
|
|
eventData->dataType = dataTypeId;
|
|
eventData->value = TelldusCore::charToWstring(sensor->value(dataTypeId).c_str());
|
|
eventData->timestamp = (int)timestamp;
|
|
d->deviceUpdateEvent->signal(eventData);
|
|
}
|
|
|
|
int DeviceManager::sendRawCommand(const std::wstring &command, int reserved) {
|
|
Controller *controller = d->controllerManager->getBestControllerById(-1);
|
|
|
|
if(!controller) {
|
|
// no controller found, scan for one, and retry once
|
|
d->controllerManager->loadControllers();
|
|
controller = d->controllerManager->getBestControllerById(-1);
|
|
}
|
|
|
|
int retval = TELLSTICK_ERROR_UNKNOWN;
|
|
if(controller) {
|
|
retval = controller->send(TelldusCore::wideToString(command));
|
|
if(retval == TELLSTICK_ERROR_BROKEN_PIPE) {
|
|
d->controllerManager->resetController(controller);
|
|
}
|
|
if(retval == TELLSTICK_ERROR_BROKEN_PIPE || retval == TELLSTICK_ERROR_NOT_FOUND) {
|
|
d->controllerManager->loadControllers();
|
|
controller = d->controllerManager->getBestControllerById(-1);
|
|
if(!controller) {
|
|
return TELLSTICK_ERROR_NOT_FOUND;
|
|
}
|
|
retval = controller->send(TelldusCore::wideToString(command)); // retry one more time
|
|
}
|
|
return retval;
|
|
} else {
|
|
return TELLSTICK_ERROR_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
bool DeviceManager::triggerDeviceStateChange(int deviceId, int intDeviceState, const std::wstring &strDeviceStateValue ) {
|
|
if ( intDeviceState == TELLSTICK_BELL || intDeviceState == TELLSTICK_LEARN || intDeviceState == TELLSTICK_EXECUTE) {
|
|
return false;
|
|
}
|
|
|
|
EventUpdateData *eventData = new EventUpdateData();
|
|
eventData->messageType = L"TDDeviceEvent";
|
|
eventData->eventState = intDeviceState;
|
|
eventData->deviceId = deviceId;
|
|
eventData->eventValue = strDeviceStateValue;
|
|
d->deviceUpdateEvent->signal(eventData);
|
|
return true;
|
|
}
|