.
This commit is contained in:
@@ -10,6 +10,14 @@
|
|||||||
<param name="color/command" textfile="$(find hos_core_types)/schema/core/types/color/command.json"/>
|
<param name="color/command" textfile="$(find hos_core_types)/schema/core/types/color/command.json"/>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
|
<group ns="/hos/types/repository/core/devices">
|
||||||
|
<param name="switch/status" textfile="$(find hos_core_types)/schema/core/devices/switch/status.json"/>
|
||||||
|
<param name="switch/command" textfile="$(find hos_core_types)/schema/core/devices/switch/command.json"/>
|
||||||
|
|
||||||
|
<param name="dimmer/status" textfile="$(find hos_core_types)/schema/core/devices/dimmer/status.json"/>
|
||||||
|
<param name="dimmer/command" textfile="$(find hos_core_types)/schema/core/devices/dimmer/command.json"/>
|
||||||
|
</group>
|
||||||
|
|
||||||
<group ns="/hos/types/repository/core/msgs">
|
<group ns="/hos/types/repository/core/msgs">
|
||||||
<param name="hosstatusupdate" textfile="$(find hos_core_types)/schema/core/msgs/hosstatusupdate.json"/>
|
<param name="hosstatusupdate" textfile="$(find hos_core_types)/schema/core/msgs/hosstatusupdate.json"/>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"title": "Dimmer Command",
|
||||||
|
"description": "",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"description": "",
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "core/devices/switch/command"
|
||||||
|
},
|
||||||
|
"dimmer": {
|
||||||
|
"$ref": "hos:schema://core/types/percentage/command"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["dimmer"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"title": "Dimmer Status",
|
||||||
|
"description": "",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"description": "",
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "core/devices/switch/status"
|
||||||
|
},
|
||||||
|
"dimmer": {
|
||||||
|
"$ref": "hos:schema://core/types/percentage/status"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["dimmer"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"title": "Switch Command",
|
||||||
|
"description": "",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"description": "",
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "core/devices/switch/command"
|
||||||
|
},
|
||||||
|
"switch": {
|
||||||
|
"$ref": "hos:schema://core/types/boolean/command"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["switch"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"title": "Switch Status",
|
||||||
|
"description": "",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"description": "",
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "core/devices/switch/status"
|
||||||
|
},
|
||||||
|
"switch": {
|
||||||
|
"$ref": "hos:schema://core/types/boolean/status"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["switch"]
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{ "required": [ "type", "set" ] },
|
{ "required": [ "set" ] },
|
||||||
{ "required": [ "type", "command" ] }
|
{ "required": [ "command" ] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -16,5 +16,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["type", "value"]
|
"required": ["value"]
|
||||||
}
|
}
|
||||||
@@ -25,8 +25,8 @@
|
|||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{ "required": [ "type", "set" ] },
|
{ "required": [ "set" ] },
|
||||||
{ "required": [ "type", "add" ] },
|
{ "required": [ "add" ] },
|
||||||
{ "required": [ "type", "sub" ] }
|
{ "required": [ "sub" ] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -16,5 +16,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["type", "value"]
|
"required": ["value"]
|
||||||
}
|
}
|
||||||
+3
@@ -6,6 +6,7 @@
|
|||||||
#include <hos/cosgi/service/interface.h>
|
#include <hos/cosgi/service/interface.h>
|
||||||
#include <Variant/Variant.h>
|
#include <Variant/Variant.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -100,6 +101,8 @@ public:
|
|||||||
|
|
||||||
virtual std::shared_ptr<Device> getDevice(std::string device_id) = 0;
|
virtual std::shared_ptr<Device> getDevice(std::string device_id) = 0;
|
||||||
virtual size_t getDevices(std::vector<std::shared_ptr<Device>>& devices) = 0;
|
virtual size_t getDevices(std::vector<std::shared_ptr<Device>>& devices) = 0;
|
||||||
|
virtual size_t deviceCount() = 0;
|
||||||
|
virtual std::set<std::string> deviceIDs() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+14
@@ -167,6 +167,20 @@ size_t DeviceRepositoryServiceImpl::getDevices(std::vector<std::shared_ptr<Devic
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t DeviceRepositoryServiceImpl::deviceCount() {
|
||||||
|
return devices.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::set<std::string> DeviceRepositoryServiceImpl::deviceIDs() {
|
||||||
|
std::set<std::string> retval;
|
||||||
|
for (auto d : devices) {
|
||||||
|
retval.insert(d.first);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepositoryServiceImpl::statusMsgCallback(const hos_core_msgs::DeviceStatusUpdate::ConstPtr& msg) {
|
void DeviceRepositoryServiceImpl::statusMsgCallback(const hos_core_msgs::DeviceStatusUpdate::ConstPtr& msg) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||||
std::cout << "HOSDeviceRepositoryServiceImpl::statusMsgCallback" << std::endl;
|
std::cout << "HOSDeviceRepositoryServiceImpl::statusMsgCallback" << std::endl;
|
||||||
|
|||||||
+2
@@ -127,6 +127,8 @@ public:
|
|||||||
|
|
||||||
virtual std::shared_ptr<Device> getDevice(std::string device_id) override;
|
virtual std::shared_ptr<Device> getDevice(std::string device_id) override;
|
||||||
virtual size_t getDevices(std::vector<std::shared_ptr<Device>>& devices) override;
|
virtual size_t getDevices(std::vector<std::shared_ptr<Device>>& devices) override;
|
||||||
|
virtual size_t deviceCount() override;
|
||||||
|
virtual std::set<std::string> deviceIDs() override;
|
||||||
|
|
||||||
/* Message Callbacks */
|
/* Message Callbacks */
|
||||||
|
|
||||||
|
|||||||
+21
-7
@@ -262,7 +262,7 @@ void DeviceStatusMsgCondition::notificationReceived(interface::Observer<devicere
|
|||||||
if (msgPointer.empty()) {
|
if (msgPointer.empty()) {
|
||||||
value = e2->statusMsg;
|
value = e2->statusMsg;
|
||||||
} else if (e2->statusMsg.HasPath(msgPointer)) {
|
} else if (e2->statusMsg.HasPath(msgPointer)) {
|
||||||
value = e2->statusMsg.Get(msgPointer);
|
value = e2->statusMsg.GetPath(msgPointer);
|
||||||
} else {
|
} else {
|
||||||
notify = false;
|
notify = false;
|
||||||
}
|
}
|
||||||
@@ -321,7 +321,7 @@ void DeviceCommandMsgCondition::notificationReceived(interface::Observer<devicer
|
|||||||
if (msgPointer.empty()) {
|
if (msgPointer.empty()) {
|
||||||
value = e2->cmdMsg;
|
value = e2->cmdMsg;
|
||||||
} else if (e2->cmdMsg.HasPath(msgPointer)) {
|
} else if (e2->cmdMsg.HasPath(msgPointer)) {
|
||||||
value = e2->cmdMsg.Get(msgPointer);
|
value = e2->cmdMsg.GetPath(msgPointer);
|
||||||
} else {
|
} else {
|
||||||
notify = false;
|
notify = false;
|
||||||
}
|
}
|
||||||
@@ -362,7 +362,15 @@ std::shared_ptr<rule::RuleCondition> DeviceStateChangeConditionFactory::createCo
|
|||||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
retval = std::make_shared<DeviceStateChangeCondition>(parent, deviceID, statePointer);
|
Variant fromValue;
|
||||||
|
if (raw.HasPath("fromvalue")) {
|
||||||
|
fromValue = raw["fromvalue"];
|
||||||
|
}
|
||||||
|
Variant toValue;
|
||||||
|
if (raw.HasPath("tovalue")) {
|
||||||
|
toValue = raw["tovalue"];
|
||||||
|
}
|
||||||
|
retval = std::make_shared<DeviceStateChangeCondition>(parent, deviceID, statePointer, fromValue, toValue);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,13 +386,19 @@ void DeviceStateChangeCondition::notificationReceived(interface::Observer<device
|
|||||||
current = device->getCurrentState();
|
current = device->getCurrentState();
|
||||||
last = device->getLastState();
|
last = device->getLastState();
|
||||||
} else if (device->getCurrentState().HasPath(msgPointer) && device->getLastState().HasPath(msgPointer)) {
|
} else if (device->getCurrentState().HasPath(msgPointer) && device->getLastState().HasPath(msgPointer)) {
|
||||||
current = device->getCurrentState().Get(msgPointer);
|
current = device->getCurrentState().GetPath(msgPointer);
|
||||||
last = device->getLastState().Get(msgPointer);
|
last = device->getLastState().GetPath(msgPointer);
|
||||||
} else {
|
} else {
|
||||||
notify = false;
|
notify = false;
|
||||||
}
|
}
|
||||||
if (notify && current == last) {
|
if (notify) {
|
||||||
notify = false;
|
if (current == last) {
|
||||||
|
notify = false;
|
||||||
|
} else if (!fromValue.IsNull() && fromValue != last) {
|
||||||
|
notify = false;
|
||||||
|
} else if (!msgValue.IsNull() && msgValue != current) {
|
||||||
|
notify = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (notify) {
|
if (notify) {
|
||||||
Variant lcontext;
|
Variant lcontext;
|
||||||
|
|||||||
@@ -115,9 +115,11 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
class DeviceStateChangeCondition : public DeviceMsgCondition {
|
class DeviceStateChangeCondition : public DeviceMsgCondition {
|
||||||
|
protected:
|
||||||
|
const Variant fromValue;
|
||||||
public:
|
public:
|
||||||
DeviceStateChangeCondition(Rule* parent, const std::string deviceID, const std::string statePointer) :
|
DeviceStateChangeCondition(Rule* parent, const std::string deviceID, const std::string statePointer, const Variant fromValue, const Variant toValue) :
|
||||||
DeviceMsgCondition(parent, Category::Event, "devicestatechange", deviceID, statePointer, Variant()) {}
|
DeviceMsgCondition(parent, Category::Event, "devicestatechange", deviceID, statePointer, toValue), fromValue(fromValue) {}
|
||||||
|
|
||||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent* e) override;
|
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent* e) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,31 +9,19 @@
|
|||||||
"conditions" : [
|
"conditions" : [
|
||||||
{
|
{
|
||||||
"type": "devicestatusmsg",
|
"type": "devicestatusmsg",
|
||||||
"deviceid": "huelight3"
|
"deviceid": "dummySwitch0",
|
||||||
},
|
"msgpointer": "/switch/value",
|
||||||
{
|
"msgvalue": true
|
||||||
"type": "devicestatechange",
|
|
||||||
"deviceid": "huelight4"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"script": { "code": "global var2\nprint \"Hello World1: \" + str(var2)\nvar2 = var2 + 1\nimport __main__\nprint \"__main__.__dict__: \" + str(__main__.__dict__)\nprint \"test: \" + event_type\ndev1 = Devices.getDevice(\"huelight1\")\nprint \"device: \" + dev1.deviceID()" },
|
"script": { "code": "global var2\nprint \"Hello World1: \" + str(var2)\nvar2 = var2 + 1\nimport __main__\nprint \"__main__.__dict__: \" + str(__main__.__dict__)\nprint \"event_type: \" + event_type\nprint \"devices: \" + str(Devices.keys())\nprint \"DeviceCount: \" + str(len(Devices))\nprint \"test: \" + str(Devices[\"dummySwitch1\"])" },
|
||||||
"exitscript": { "code": "print \"Hello from exitscript1\"" }
|
"exitscript": { "code": "print \"Hello from exitscript1\"" }
|
||||||
},
|
},
|
||||||
"rule02": {
|
"rule02": {
|
||||||
"condition": {
|
"condition": {
|
||||||
"type": "logical_or",
|
"type": "devicestatechange",
|
||||||
"$schema": "hos:schema://core/configs/rulepackage#/definitions/LogicalOrCondition",
|
"deviceid": "dummySwitch0"
|
||||||
"conditions" : [
|
|
||||||
{
|
|
||||||
"type": "devicecommandmsg",
|
|
||||||
"deviceid": "huelight4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "devicestatechange",
|
|
||||||
"deviceid": "huelight3"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"script": { "code": "print \"Hello World2: \" + str(var2)\nvar2 = var2 + 1\nimport __main__\nprint \"__main__.__dict__: \" + str(__main__.__dict__)\nprint \"test: \" + event_type" },
|
"script": { "code": "print \"Hello World2: \" + str(var2)\nvar2 = var2 + 1\nimport __main__\nprint \"__main__.__dict__: \" + str(__main__.__dict__)\nprint \"test: \" + event_type" },
|
||||||
"exitscript": { "code": "print \"Hello from exitscript2\"" }
|
"exitscript": { "code": "print \"Hello from exitscript2\"" }
|
||||||
@@ -45,16 +33,42 @@
|
|||||||
"conditions" : [
|
"conditions" : [
|
||||||
{
|
{
|
||||||
"type": "devicecommandmsg",
|
"type": "devicecommandmsg",
|
||||||
"deviceid": "huelight1"
|
"deviceid": "dummySwitch0"
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "devicestatechange",
|
|
||||||
"deviceid": "huelight2"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"script": { "code": "print \"Hello World3: \" + str(var2)\nvar2 = var2 + 1\nimport __main__\nprint \"__main__.__dict__: \" + str(__main__.__dict__)\nprint \"test: \" + event_type" },
|
"script": { "code": "print \"Hello World3: \" + str(var2)\nvar2 = var2 + 1\nimport __main__\nprint \"__main__.__dict__: \" + str(__main__.__dict__)\nprint \"test: \" + event_type" },
|
||||||
"exitscript": { "code": "print \"Hello from exitscript2\"" }
|
"exitscript": { "code": "print \"Hello from exitscript2\"" }
|
||||||
|
},
|
||||||
|
"rule04": {
|
||||||
|
"condition": {
|
||||||
|
"type": "logical_or",
|
||||||
|
"$schema": "hos:schema://core/configs/rulepackage#/definitions/LogicalOrCondition",
|
||||||
|
"conditions" : [
|
||||||
|
{
|
||||||
|
"type": "devicestatechange",
|
||||||
|
"deviceid": "dummyDimmer0",
|
||||||
|
"msgpointer": "/dimmer/value",
|
||||||
|
"tovalue": 1.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"script": { "code": "print \"Dimmer 0 reached 100\"" }
|
||||||
|
},
|
||||||
|
"rule05": {
|
||||||
|
"condition": {
|
||||||
|
"type": "logical_or",
|
||||||
|
"$schema": "hos:schema://core/configs/rulepackage#/definitions/LogicalOrCondition",
|
||||||
|
"conditions" : [
|
||||||
|
{
|
||||||
|
"type": "devicestatechange",
|
||||||
|
"deviceid": "dummyDimmer0",
|
||||||
|
"msgpointer": "/dimmer",
|
||||||
|
"fromvalue": { "value": 1.0 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"script": { "code": "print \"Dimmer 0 left 100\"" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,6 +123,7 @@ bundle(hos_cosgi_scripting_python
|
|||||||
SOURCES
|
SOURCES
|
||||||
${PROJECT_SOURCE_DIR}/src/bundle_activator
|
${PROJECT_SOURCE_DIR}/src/bundle_activator
|
||||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/scripting_serviceimpl
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/scripting_serviceimpl
|
||||||
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/PyHOSAPI
|
||||||
)
|
)
|
||||||
target_link_libraries(hos_cosgi_scripting_python
|
target_link_libraries(hos_cosgi_scripting_python
|
||||||
${catkin_LIBRARIES}
|
${catkin_LIBRARIES}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* PyHOSAPI.cpp
|
||||||
|
*
|
||||||
|
* Created on: 19.05.2015
|
||||||
|
* Author: matzman
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "PyHOSAPI.h"
|
||||||
|
#include <ros/ros.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace scripting {
|
||||||
|
namespace python {
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_PYTHON_MODULE(hos)
|
||||||
|
{
|
||||||
|
using namespace boost::python;
|
||||||
|
|
||||||
|
class_<PyDeviceWrapper>("Device", no_init)
|
||||||
|
.def("deviceID", &PyDeviceWrapper::deviceID) ;
|
||||||
|
|
||||||
|
class_<PyDeviceRepositoryWrapper>("DeviceRepository", no_init)
|
||||||
|
.def("getDevice", &PyDeviceRepositoryWrapper::getDevice)
|
||||||
|
.def("__getitem__", &PyDeviceRepositoryWrapper::getDevice)
|
||||||
|
.def("__len__", &PyDeviceRepositoryWrapper::deviceCount)
|
||||||
|
.def("keys", &PyDeviceRepositoryWrapper::deviceIDs) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::python::object convertVariantToBoostPython(Variant var) {
|
||||||
|
if (var.IsBool()) {
|
||||||
|
return boost::python::object(var.AsBool());
|
||||||
|
} else if (var.IsFloat()) {
|
||||||
|
return boost::python::object(var.AsDouble());
|
||||||
|
} else if (var.IsInt()) {
|
||||||
|
return boost::python::object(var.AsInt());
|
||||||
|
} else if (var.IsString()) {
|
||||||
|
return boost::python::str(var.AsString());
|
||||||
|
} else if (var.IsUnsigned()) {
|
||||||
|
return boost::python::object(var.AsUnsigned());
|
||||||
|
} else if (var.IsList()) {
|
||||||
|
boost::python::list list;
|
||||||
|
for (auto e : var.AsList()) {
|
||||||
|
list.append(convertVariantToBoostPython(e));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
} else if (var.IsMap()) {
|
||||||
|
boost::python::dict map;
|
||||||
|
for (auto e : var.AsMap()) {
|
||||||
|
map[e.first] = convertVariantToBoostPython(e.second);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
} else {
|
||||||
|
ROS_ERROR("Unknown Variant type encountered while converting to python");
|
||||||
|
return boost::python::object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace python
|
||||||
|
} // namespace scripting
|
||||||
|
} // namespace service
|
||||||
|
} // namespace cosgi
|
||||||
|
} // namespace hos
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* PyHOSAPI.h
|
||||||
|
*
|
||||||
|
* Created on: 19.05.2015
|
||||||
|
* Author: matzman
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_PYHOSAPI_H_
|
||||||
|
#define SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_PYHOSAPI_H_
|
||||||
|
|
||||||
|
#include <boost/python.hpp>
|
||||||
|
#include <hos/cosgi/service/scripting/scripting_service.h>
|
||||||
|
#include <hos/cosgi/service/devicerepository/devicerepository_service.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace scripting {
|
||||||
|
namespace python {
|
||||||
|
|
||||||
|
class PyScriptingService;
|
||||||
|
|
||||||
|
|
||||||
|
boost::python::object convertVariantToBoostPython(Variant var);
|
||||||
|
|
||||||
|
class PyDeviceWrapper {
|
||||||
|
private:
|
||||||
|
devicerepository::Device* device;
|
||||||
|
public:
|
||||||
|
PyDeviceWrapper(devicerepository::Device* device) : device(device) {}
|
||||||
|
|
||||||
|
std::string deviceID() { return device->getDeviceID(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class PyDeviceRepositoryWrapper {
|
||||||
|
private:
|
||||||
|
devicerepository::DeviceRepositoryService* service;
|
||||||
|
public:
|
||||||
|
PyDeviceRepositoryWrapper(devicerepository::DeviceRepositoryService* service) : service(service) {}
|
||||||
|
|
||||||
|
PyDeviceWrapper getDevice(std::string name) {
|
||||||
|
return PyDeviceWrapper(service->getDevice(name).get());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t deviceCount() {
|
||||||
|
return service->deviceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::python::list deviceIDs() {
|
||||||
|
boost::python::list retval;
|
||||||
|
for (auto d : service->deviceIDs()) {
|
||||||
|
retval.append(d);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" void inithos();
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace python
|
||||||
|
} // namespace scripting
|
||||||
|
} // namespace service
|
||||||
|
} // namespace cosgi
|
||||||
|
} // namespace hos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_PYHOSAPI_H_ */
|
||||||
+1
-63
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "scripting_serviceimpl.h"
|
#include "scripting_serviceimpl.h"
|
||||||
|
#include "PyHOSAPI.h"
|
||||||
|
|
||||||
#include <hos/cosgi/service/core/core_service.h>
|
#include <hos/cosgi/service/core/core_service.h>
|
||||||
#include <hos/cosgi/service/devicerepository/devicerepository_service.h>
|
#include <hos/cosgi/service/devicerepository/devicerepository_service.h>
|
||||||
@@ -81,39 +82,6 @@ std::shared_ptr<service::scripting::Script> PyScriptingService::createScript(ser
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PyDeviceWrapper {
|
|
||||||
private:
|
|
||||||
devicerepository::Device* device;
|
|
||||||
public:
|
|
||||||
PyDeviceWrapper(devicerepository::Device* device) : device(device) {}
|
|
||||||
|
|
||||||
std::string deviceID() { return device->getDeviceID(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class PyDeviceRepositoryWrapper {
|
|
||||||
private:
|
|
||||||
devicerepository::DeviceRepositoryService* service;
|
|
||||||
public:
|
|
||||||
PyDeviceRepositoryWrapper(devicerepository::DeviceRepositoryService* service) : service(service) {}
|
|
||||||
|
|
||||||
PyDeviceWrapper getDevice(std::string name) {
|
|
||||||
return PyDeviceWrapper(service->getDevice(name).get());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_PYTHON_MODULE(hos)
|
|
||||||
{
|
|
||||||
using namespace boost::python;
|
|
||||||
|
|
||||||
class_<PyDeviceWrapper>("Device", no_init)
|
|
||||||
.def("deviceID", &PyDeviceWrapper::deviceID) ;
|
|
||||||
|
|
||||||
class_<PyDeviceRepositoryWrapper>("DeviceRepository", no_init)
|
|
||||||
.def("getDevice", &PyDeviceRepositoryWrapper::getDevice) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PyScript::exec(service::scripting::GlobalScriptContext* gContext, Variant lContext) {
|
void PyScript::exec(service::scripting::GlobalScriptContext* gContext, Variant lContext) {
|
||||||
@@ -141,36 +109,6 @@ void PyScript::exec(service::scripting::GlobalScriptContext* gContext, Variant l
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
boost::python::object convertVariantToBoostPython(Variant var) {
|
|
||||||
if (var.IsBool()) {
|
|
||||||
return boost::python::object(var.AsBool());
|
|
||||||
} else if (var.IsFloat()) {
|
|
||||||
return boost::python::object(var.AsDouble());
|
|
||||||
} else if (var.IsInt()) {
|
|
||||||
return boost::python::object(var.AsInt());
|
|
||||||
} else if (var.IsString()) {
|
|
||||||
return boost::python::str(var.AsString());
|
|
||||||
} else if (var.IsUnsigned()) {
|
|
||||||
return boost::python::object(var.AsUnsigned());
|
|
||||||
} else if (var.IsList()) {
|
|
||||||
boost::python::list list;
|
|
||||||
for (auto e : var.AsList()) {
|
|
||||||
list.append(convertVariantToBoostPython(e));
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
} else if (var.IsMap()) {
|
|
||||||
boost::python::dict map;
|
|
||||||
for (auto e : var.AsMap()) {
|
|
||||||
map[e.first] = convertVariantToBoostPython(e.second);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
} else {
|
|
||||||
ROS_ERROR("Unknown Variant type encountered while converting to python");
|
|
||||||
return boost::python::object();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace python
|
} // namespace python
|
||||||
} // namespace ruleengine
|
} // namespace ruleengine
|
||||||
|
|||||||
-1
@@ -99,7 +99,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
boost::python::object convertVariantToBoostPython(Variant var);
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace python
|
} // namespace python
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8.3)
|
||||||
|
project(hos_dummy)
|
||||||
|
|
||||||
|
## Find catkin macros and libraries
|
||||||
|
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
|
||||||
|
## is used, also find other catkin packages
|
||||||
|
find_package(catkin REQUIRED COMPONENTS
|
||||||
|
hos_core_msgs
|
||||||
|
hos_python_json
|
||||||
|
rospy
|
||||||
|
)
|
||||||
|
|
||||||
|
## System dependencies are found with CMake's conventions
|
||||||
|
# find_package(Boost REQUIRED COMPONENTS system)
|
||||||
|
|
||||||
|
|
||||||
|
## Uncomment this if the package has a setup.py. This macro ensures
|
||||||
|
## modules and global scripts declared therein get installed
|
||||||
|
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
|
||||||
|
catkin_python_setup()
|
||||||
|
|
||||||
|
################################################
|
||||||
|
## Declare ROS messages, services and actions ##
|
||||||
|
################################################
|
||||||
|
|
||||||
|
## To declare and build messages, services or actions from within this
|
||||||
|
## package, follow these steps:
|
||||||
|
## * Let MSG_DEP_SET be the set of packages whose message types you use in
|
||||||
|
## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
|
||||||
|
## * In the file package.xml:
|
||||||
|
## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET
|
||||||
|
## * If MSG_DEP_SET isn't empty the following dependencies might have been
|
||||||
|
## pulled in transitively but can be declared for certainty nonetheless:
|
||||||
|
## * add a build_depend tag for "message_generation"
|
||||||
|
## * add a run_depend tag for "message_runtime"
|
||||||
|
## * In this file (CMakeLists.txt):
|
||||||
|
## * add "message_generation" and every package in MSG_DEP_SET to
|
||||||
|
## find_package(catkin REQUIRED COMPONENTS ...)
|
||||||
|
## * add "message_runtime" and every package in MSG_DEP_SET to
|
||||||
|
## catkin_package(CATKIN_DEPENDS ...)
|
||||||
|
## * uncomment the add_*_files sections below as needed
|
||||||
|
## and list every .msg/.srv/.action file to be processed
|
||||||
|
## * uncomment the generate_messages entry below
|
||||||
|
## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
|
||||||
|
|
||||||
|
## Generate messages in the 'msg' folder
|
||||||
|
# add_message_files(
|
||||||
|
# FILES
|
||||||
|
# Message1.msg
|
||||||
|
# Message2.msg
|
||||||
|
# )
|
||||||
|
|
||||||
|
## Generate services in the 'srv' folder
|
||||||
|
# add_service_files(
|
||||||
|
# FILES
|
||||||
|
# Service1.srv
|
||||||
|
# Service2.srv
|
||||||
|
# )
|
||||||
|
|
||||||
|
## Generate actions in the 'action' folder
|
||||||
|
# add_action_files(
|
||||||
|
# FILES
|
||||||
|
# Action1.action
|
||||||
|
# Action2.action
|
||||||
|
# )
|
||||||
|
|
||||||
|
## Generate added messages and services with any dependencies listed here
|
||||||
|
# generate_messages(
|
||||||
|
# DEPENDENCIES
|
||||||
|
# hos_core_msgs
|
||||||
|
# )
|
||||||
|
|
||||||
|
###################################
|
||||||
|
## catkin specific configuration ##
|
||||||
|
###################################
|
||||||
|
## The catkin_package macro generates cmake config files for your package
|
||||||
|
## Declare things to be passed to dependent projects
|
||||||
|
## INCLUDE_DIRS: uncomment this if you package contains header files
|
||||||
|
## LIBRARIES: libraries you create in this project that dependent projects also need
|
||||||
|
## CATKIN_DEPENDS: catkin_packages dependent projects also need
|
||||||
|
## DEPENDS: system dependencies of this project that dependent projects also need
|
||||||
|
catkin_package(
|
||||||
|
# INCLUDE_DIRS include
|
||||||
|
# LIBRARIES hos_dummy
|
||||||
|
CATKIN_DEPENDS hos_core_msgs hos_python_json rospy
|
||||||
|
# DEPENDS system_lib
|
||||||
|
)
|
||||||
|
|
||||||
|
###########
|
||||||
|
## Build ##
|
||||||
|
###########
|
||||||
|
|
||||||
|
## Specify additional locations of header files
|
||||||
|
## Your package locations should be listed before other locations
|
||||||
|
# include_directories(include)
|
||||||
|
include_directories(
|
||||||
|
${catkin_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
## Declare a cpp library
|
||||||
|
# add_library(hos_dummy
|
||||||
|
# src/${PROJECT_NAME}/hos_dummy.cpp
|
||||||
|
# )
|
||||||
|
|
||||||
|
## Declare a cpp executable
|
||||||
|
# add_executable(hos_dummy_node src/hos_dummy_node.cpp)
|
||||||
|
|
||||||
|
## Add cmake target dependencies of the executable/library
|
||||||
|
## as an example, message headers may need to be generated before nodes
|
||||||
|
# add_dependencies(hos_dummy_node hos_dummy_generate_messages_cpp)
|
||||||
|
|
||||||
|
## Specify libraries to link a library or executable target against
|
||||||
|
# target_link_libraries(hos_dummy_node
|
||||||
|
# ${catkin_LIBRARIES}
|
||||||
|
# )
|
||||||
|
|
||||||
|
#############
|
||||||
|
## Install ##
|
||||||
|
#############
|
||||||
|
|
||||||
|
|
||||||
|
#And this will install python nodes
|
||||||
|
catkin_install_python(PROGRAMS
|
||||||
|
nodes/hos_dummy_devices.py
|
||||||
|
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
|
||||||
|
|
||||||
|
# all install targets should use catkin DESTINATION variables
|
||||||
|
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
|
||||||
|
|
||||||
|
## Mark executable scripts (Python etc.) for installation
|
||||||
|
## in contrast to setup.py, you can choose the destination
|
||||||
|
# install(PROGRAMS
|
||||||
|
# scripts/my_python_script
|
||||||
|
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||||
|
# )
|
||||||
|
|
||||||
|
## Mark executables and/or libraries for installation
|
||||||
|
# install(TARGETS hos_dummy hos_dummy_node
|
||||||
|
# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
|
||||||
|
# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
|
||||||
|
# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||||
|
# )
|
||||||
|
|
||||||
|
## Mark cpp header files for installation
|
||||||
|
# install(DIRECTORY include/${PROJECT_NAME}/
|
||||||
|
# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
|
||||||
|
# FILES_MATCHING PATTERN "*.h"
|
||||||
|
# PATTERN ".svn" EXCLUDE
|
||||||
|
# )
|
||||||
|
|
||||||
|
## Mark other files for installation (e.g. launch and bag files, etc.)
|
||||||
|
# install(FILES
|
||||||
|
# # myfile1
|
||||||
|
# # myfile2
|
||||||
|
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
|
||||||
|
# )
|
||||||
|
|
||||||
|
#############
|
||||||
|
## Testing ##
|
||||||
|
#############
|
||||||
|
|
||||||
|
## Add gtest based cpp test target and link libraries
|
||||||
|
# catkin_add_gtest(${PROJECT_NAME}-test test/test_hos_dummy.cpp)
|
||||||
|
# if(TARGET ${PROJECT_NAME}-test)
|
||||||
|
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
|
||||||
|
# endif()
|
||||||
|
|
||||||
|
## Add folders to be run by python nosetests
|
||||||
|
# catkin_add_nosetests(test)
|
||||||
Executable
+28
@@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import socket
|
||||||
|
import rospy
|
||||||
|
import traceback
|
||||||
|
from hos_core_msgs.msg import DeviceCommand
|
||||||
|
from hos_dummy.HosDummyController import HosDummyController
|
||||||
|
|
||||||
|
import Tkinter as tk
|
||||||
|
import Tkconstants
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
root = tk.Tk();
|
||||||
|
app = HosDummyController(root)
|
||||||
|
root.geometry("+200+200")
|
||||||
|
app.master.title('HOS Dummy Controller')
|
||||||
|
|
||||||
|
app.mainloop()
|
||||||
|
except socket.error as e:
|
||||||
|
print "Could not connect to master"
|
||||||
|
except Exception as inst:
|
||||||
|
print type(inst) # the exception instance
|
||||||
|
print inst # __str__ allows args to be printed directly
|
||||||
|
traceback.print_exc()
|
||||||
Executable
+33
@@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import socket
|
||||||
|
import rospy
|
||||||
|
import traceback
|
||||||
|
from hos_core_msgs.msg import DeviceCommand
|
||||||
|
from hos_dummy.HosDummyDevices import HosDummyDevices
|
||||||
|
|
||||||
|
import Tkinter as tk
|
||||||
|
import Tkconstants
|
||||||
|
|
||||||
|
|
||||||
|
def deviceCmdCallback(data):
|
||||||
|
app.deviceCmdCallback(data)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
root = tk.Tk();
|
||||||
|
app = HosDummyDevices(root)
|
||||||
|
root.geometry("+200+200")
|
||||||
|
app.master.title('HOS Dummy Devices')
|
||||||
|
|
||||||
|
rospy.Subscriber(app.cmd_topic, DeviceCommand, deviceCmdCallback)
|
||||||
|
|
||||||
|
app.mainloop()
|
||||||
|
except socket.error as e:
|
||||||
|
print "Could not connect to master"
|
||||||
|
except Exception as inst:
|
||||||
|
print type(inst) # the exception instance
|
||||||
|
print inst # __str__ allows args to be printed directly
|
||||||
|
traceback.print_exc()
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<package>
|
||||||
|
<name>hos_dummy</name>
|
||||||
|
<version>0.0.0</version>
|
||||||
|
<description>The hos_dummy package</description>
|
||||||
|
|
||||||
|
<!-- One maintainer tag required, multiple allowed, one person per tag -->
|
||||||
|
<!-- Example: -->
|
||||||
|
<!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
|
||||||
|
<maintainer email="matzman@todo.todo">matzman</maintainer>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- One license tag required, multiple allowed, one license per tag -->
|
||||||
|
<!-- Commonly used license strings: -->
|
||||||
|
<!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
|
||||||
|
<license>TODO</license>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Url tags are optional, but mutiple are allowed, one per tag -->
|
||||||
|
<!-- Optional attribute type can be: website, bugtracker, or repository -->
|
||||||
|
<!-- Example: -->
|
||||||
|
<!-- <url type="website">http://wiki.ros.org/hos_dummy</url> -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Author tags are optional, mutiple are allowed, one per tag -->
|
||||||
|
<!-- Authors do not have to be maintianers, but could be -->
|
||||||
|
<!-- Example: -->
|
||||||
|
<!-- <author email="jane.doe@example.com">Jane Doe</author> -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- The *_depend tags are used to specify dependencies -->
|
||||||
|
<!-- Dependencies can be catkin packages or system dependencies -->
|
||||||
|
<!-- Examples: -->
|
||||||
|
<!-- Use build_depend for packages you need at compile time: -->
|
||||||
|
<!-- <build_depend>message_generation</build_depend> -->
|
||||||
|
<!-- Use buildtool_depend for build tool packages: -->
|
||||||
|
<!-- <buildtool_depend>catkin</buildtool_depend> -->
|
||||||
|
<!-- Use run_depend for packages you need at runtime: -->
|
||||||
|
<!-- <run_depend>message_runtime</run_depend> -->
|
||||||
|
<!-- Use test_depend for packages you need only for testing: -->
|
||||||
|
<!-- <test_depend>gtest</test_depend> -->
|
||||||
|
<buildtool_depend>catkin</buildtool_depend>
|
||||||
|
<build_depend>hos_core_msgs</build_depend>
|
||||||
|
<build_depend>hos_python_json</build_depend>
|
||||||
|
<build_depend>rospy</build_depend>
|
||||||
|
<run_depend>hos_core_msgs</run_depend>
|
||||||
|
<run_depend>hos_python_json</run_depend>
|
||||||
|
<run_depend>rospy</run_depend>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- The export tag contains other, unspecified, tags -->
|
||||||
|
<export>
|
||||||
|
<!-- Other tools can request additional information be placed here -->
|
||||||
|
|
||||||
|
</export>
|
||||||
|
</package>
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import rospy
|
||||||
|
import json
|
||||||
|
from hos_pyhue import pyhue
|
||||||
|
from hos_core_msgs.msg import DeviceCommand
|
||||||
|
from hos_core_msgs.msg import DeviceStatusUpdate
|
||||||
|
from hos_core_msgs.msg import HosStatusUpdate
|
||||||
|
from jsonspec_hos.reference.providers import HOSParamServerProvider
|
||||||
|
from jsonspec.validators import load
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
import Tkinter as tk
|
||||||
|
import Tkconstants
|
||||||
|
|
||||||
|
|
||||||
|
class HosDummyController(tk.Frame):
|
||||||
|
def __init__(self, master=None):
|
||||||
|
# Init ROS node
|
||||||
|
rospy.init_node('hos_dummy_controller', argv=sys.argv)
|
||||||
|
# Get ROS parameter
|
||||||
|
self.status_topic = rospy.get_param('~status_topic', "/hos/devices/status")
|
||||||
|
self.cmd_topic = rospy.get_param('~cmd_topic', "/hos/devices/cmd")
|
||||||
|
self.hos_update_topic = rospy.get_param('~hos_update_topic', "/hos/status/updates")
|
||||||
|
self.loop_frequency = rospy.get_param('~loop_frequency', 100)
|
||||||
|
self.statusmsg_interval = rospy.get_param('~statusmsg_interval', 6000000)
|
||||||
|
# Init Variables
|
||||||
|
self.msg_sequence = 0
|
||||||
|
# Init devices
|
||||||
|
self.switches = dict()
|
||||||
|
self.dimmers = dict()
|
||||||
|
for i in range(4):
|
||||||
|
# switches
|
||||||
|
name = "dummySwitch" + str(i)
|
||||||
|
self.switches[i] = dict()
|
||||||
|
self.switches[i]["value"] = False
|
||||||
|
self.switches[i]["id"] = name
|
||||||
|
self.switches[i]["name"] = "Switch " + str(i)
|
||||||
|
key_base = "/hos/devices/repository/" + name
|
||||||
|
rospy.set_param(key_base + "/type", "core/devices/switch")
|
||||||
|
rospy.set_param(key_base + "/status_topic", self.status_topic)
|
||||||
|
rospy.set_param(key_base + "/cmd_topic", self.cmd_topic)
|
||||||
|
print "Added dummy switch \"" + name + "\""
|
||||||
|
# dimmers
|
||||||
|
name = "dummyDimmer" + str(i)
|
||||||
|
self.dimmers[i] = dict()
|
||||||
|
self.dimmers[i]["value"] = 0.0
|
||||||
|
self.dimmers[i]["id"] = name
|
||||||
|
self.dimmers[i]["name"] = "Dimmer " + str(i)
|
||||||
|
key_base = "/hos/devices/repository/" + name
|
||||||
|
rospy.set_param(key_base + "/type", "core/devices/switch")
|
||||||
|
rospy.set_param(key_base + "/status_topic", self.status_topic)
|
||||||
|
rospy.set_param(key_base + "/cmd_topic", self.cmd_topic)
|
||||||
|
print "Added dummy dimmer \"" + name + "\""
|
||||||
|
# Create JSON schema provider
|
||||||
|
self.schemaProvider = HOSParamServerProvider()
|
||||||
|
# Create message publisher
|
||||||
|
self.commandPublisher = rospy.Publisher(self.cmd_topic, DeviceCommand, queue_size=10)
|
||||||
|
# Init GUI
|
||||||
|
tk.Frame.__init__(self, master, padx="10px", pady="10px")
|
||||||
|
self.grid()
|
||||||
|
self.createWidgets()
|
||||||
|
|
||||||
|
|
||||||
|
def createWidgets(self):
|
||||||
|
self.switchframe = tk.LabelFrame(self, text = "Switches", relief=Tkconstants.SUNKEN, bd=1)
|
||||||
|
self.switchframe.grid(column=0, row=0)
|
||||||
|
for i in range(4):
|
||||||
|
self.switches[i]["intvar"] = tk.IntVar(value=int(self.switches[i]["value"]))
|
||||||
|
self.switches[i]["checkbutton"] = tk.Checkbutton(self.switchframe, text=self.switches[i]["name"], variable = self.switches[i]["intvar"], onvalue = 1, offvalue = 0, height=5, width = 20, command=self.switchCallback)
|
||||||
|
self.switches[i]["checkbutton"].grid(column=0, row=i)
|
||||||
|
|
||||||
|
self.dimmerframe = tk.LabelFrame(self, text = "Dimmers", relief=Tkconstants.SUNKEN, bd=1)
|
||||||
|
self.dimmerframe.grid(column=1, row=0)
|
||||||
|
for i in range(4):
|
||||||
|
self.dimmers[i]["doublevar"] = tk.DoubleVar(value=float(self.dimmers[i]["value"]))
|
||||||
|
self.dimmers[i]["label"] = tk.Label(self.dimmerframe, text=self.dimmers[i]["name"])
|
||||||
|
self.dimmers[i]["label"].grid(column=0, row=i)
|
||||||
|
self.dimmers[i]["scale"] = tk.Scale( self.dimmerframe, variable = self.dimmers[i]["doublevar"], from_=0.0, to=100.0, command=self.scaleCallback)
|
||||||
|
self.dimmers[i]["scale"].grid(column=1, row=i)
|
||||||
|
|
||||||
|
#self.quitButton = tk.Button(self, text='Quit', command=self.quit)
|
||||||
|
#self.quitButton.grid()
|
||||||
|
|
||||||
|
|
||||||
|
def createSwitchMsg(self, switch, seq, stamp):
|
||||||
|
msg = DeviceCommand()
|
||||||
|
msg.seq = seq
|
||||||
|
msg.device_id = switch["id"]
|
||||||
|
msg.device_type = "core/devices/switch"
|
||||||
|
msg.stamp = stamp
|
||||||
|
|
||||||
|
msg_body = dict()
|
||||||
|
|
||||||
|
msg_body["switch"] = dict()
|
||||||
|
msg_body["switch"]["set"] = switch["value"]
|
||||||
|
|
||||||
|
msg_schema = self.schemaProvider.getTypeSchema("core/devices/switch/command")
|
||||||
|
validator = load(msg_schema, provider=self.schemaProvider)
|
||||||
|
|
||||||
|
validator.validate(msg_body)
|
||||||
|
|
||||||
|
msg.msg_body = json.dumps(msg_body)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def createDimmerMsg(self, dimmer, seq, stamp):
|
||||||
|
msg = DeviceCommand()
|
||||||
|
msg.seq = seq
|
||||||
|
msg.device_id = dimmer["id"]
|
||||||
|
msg.device_type = "core/devices/dimmer"
|
||||||
|
msg.stamp = stamp
|
||||||
|
|
||||||
|
msg_body = dict()
|
||||||
|
|
||||||
|
msg_body["dimmer"] = dict()
|
||||||
|
msg_body["dimmer"]["set"] = dimmer["value"]/100.0
|
||||||
|
|
||||||
|
msg_schema = self.schemaProvider.getTypeSchema("core/devices/dimmer/command")
|
||||||
|
validator = load(msg_schema, provider=self.schemaProvider)
|
||||||
|
validator.validate(msg_body)
|
||||||
|
|
||||||
|
msg.msg_body = json.dumps(msg_body)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def scaleCallback(self, newvalue):
|
||||||
|
stamp = rospy.get_rostime()
|
||||||
|
for i in self.dimmers:
|
||||||
|
if (self.dimmers[i]["value"] != self.dimmers[i]["doublevar"].get()):
|
||||||
|
self.dimmers[i]["value"] = float(self.dimmers[i]["doublevar"].get())
|
||||||
|
self.commandPublisher.publish(self.createDimmerMsg(self.dimmers[i], self.msg_sequence, stamp))
|
||||||
|
self.msg_sequence += 1
|
||||||
|
|
||||||
|
|
||||||
|
def switchCallback(self):
|
||||||
|
stamp = rospy.get_rostime()
|
||||||
|
for i in self.switches:
|
||||||
|
if (self.switches[i]["value"] != bool(self.switches[i]["intvar"].get())):
|
||||||
|
self.switches[i]["value"] = bool(self.switches[i]["intvar"].get())
|
||||||
|
self.commandPublisher.publish(self.createSwitchMsg(self.switches[i], self.msg_sequence, stamp))
|
||||||
|
self.msg_sequence += 1
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import rospy
|
||||||
|
import json
|
||||||
|
from hos_pyhue import pyhue
|
||||||
|
from hos_core_msgs.msg import DeviceCommand
|
||||||
|
from hos_core_msgs.msg import DeviceStatusUpdate
|
||||||
|
from hos_core_msgs.msg import HosStatusUpdate
|
||||||
|
from jsonspec_hos.reference.providers import HOSParamServerProvider
|
||||||
|
from jsonspec.validators import load
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
import Tkinter as tk
|
||||||
|
import Tkconstants
|
||||||
|
|
||||||
|
|
||||||
|
class HosDummyDevices(tk.Frame):
|
||||||
|
def __init__(self, master=None):
|
||||||
|
# Init ROS node
|
||||||
|
rospy.init_node('hos_dummy_devices', argv=sys.argv)
|
||||||
|
# Get ROS parameter
|
||||||
|
self.status_topic = rospy.get_param('~status_topic', "/hos/devices/status")
|
||||||
|
self.cmd_topic = rospy.get_param('~cmd_topic', "/hos/devices/cmd")
|
||||||
|
self.hos_update_topic = rospy.get_param('~hos_update_topic', "/hos/status/updates")
|
||||||
|
self.loop_frequency = rospy.get_param('~loop_frequency', 100)
|
||||||
|
self.statusmsg_interval = rospy.get_param('~statusmsg_interval', 6000000)
|
||||||
|
# Init Variables
|
||||||
|
self.msg_sequence = 0
|
||||||
|
# Init devices
|
||||||
|
new_devices = list()
|
||||||
|
self.switches = dict()
|
||||||
|
self.dimmers = dict()
|
||||||
|
for i in range(4):
|
||||||
|
# switches
|
||||||
|
name = "dummySwitch" + str(i)
|
||||||
|
self.switches[i] = dict()
|
||||||
|
self.switches[i]["value"] = False
|
||||||
|
self.switches[i]["id"] = name
|
||||||
|
self.switches[i]["name"] = "Switch " + str(i)
|
||||||
|
key_base = "/hos/devices/repository/" + name
|
||||||
|
rospy.set_param(key_base + "/type", "core/devices/switch")
|
||||||
|
rospy.set_param(key_base + "/status_topic", self.status_topic)
|
||||||
|
rospy.set_param(key_base + "/cmd_topic", self.cmd_topic)
|
||||||
|
print "Added dummy switch \"" + name + "\""
|
||||||
|
new_devices.append(name)
|
||||||
|
# dimmers
|
||||||
|
name = "dummyDimmer" + str(i)
|
||||||
|
self.dimmers[i] = dict()
|
||||||
|
self.dimmers[i]["value"] = 0.0
|
||||||
|
self.dimmers[i]["id"] = name
|
||||||
|
self.dimmers[i]["name"] = "Dimmer " + str(i)
|
||||||
|
key_base = "/hos/devices/repository/" + name
|
||||||
|
rospy.set_param(key_base + "/type", "core/devices/switch")
|
||||||
|
rospy.set_param(key_base + "/status_topic", self.status_topic)
|
||||||
|
rospy.set_param(key_base + "/cmd_topic", self.cmd_topic)
|
||||||
|
print "Added dummy dimmer \"" + name + "\""
|
||||||
|
new_devices.append(name)
|
||||||
|
# Create JSON schema provider
|
||||||
|
self.schemaProvider = HOSParamServerProvider()
|
||||||
|
# Create message publisher
|
||||||
|
self.statusPublisher = rospy.Publisher(self.status_topic, DeviceStatusUpdate, queue_size=10)
|
||||||
|
self.hosUpdatePublisher = rospy.Publisher(self.hos_update_topic, HosStatusUpdate, queue_size=10)
|
||||||
|
# Send HOS Status Update Message
|
||||||
|
updMsg = HosStatusUpdate()
|
||||||
|
stamp = rospy.get_rostime()
|
||||||
|
updMsg.stamp = stamp
|
||||||
|
updMsg.tags.append("devices")
|
||||||
|
updBody = dict()
|
||||||
|
updBody["type"] = "core/msgs/hosstatusupdate"
|
||||||
|
updBody["devices"] = dict()
|
||||||
|
updBody["devices"]["type"] = "core/msgs/hosstatusupdate/devices";
|
||||||
|
updBody["devices"]["added"] = new_devices
|
||||||
|
|
||||||
|
msg_schema = self.schemaProvider.getTypeSchema("core/msgs/hosstatusupdate")
|
||||||
|
validator = load(msg_schema, provider=self.schemaProvider)
|
||||||
|
validator.validate(updBody)
|
||||||
|
|
||||||
|
updMsg.msg_body = json.dumps(updBody)
|
||||||
|
sleep(1) # Apparently we need to wait before we can send messages
|
||||||
|
self.hosUpdatePublisher.publish(updMsg)
|
||||||
|
|
||||||
|
# Init GUI
|
||||||
|
tk.Frame.__init__(self, master, padx="10px", pady="10px")
|
||||||
|
self.grid()
|
||||||
|
self.createWidgets()
|
||||||
|
|
||||||
|
self.deviceStatusCallback()
|
||||||
|
|
||||||
|
|
||||||
|
def createWidgets(self):
|
||||||
|
self.switchframe = tk.LabelFrame(self, text = "Switches", relief=Tkconstants.SUNKEN, bd=1)
|
||||||
|
self.switchframe.grid(column=0, row=0)
|
||||||
|
for i in range(4):
|
||||||
|
self.switches[i]["stringvar"] = tk.StringVar(value=str(self.switches[i]["value"]))
|
||||||
|
self.switches[i]["label1"] = tk.Label(self.switchframe, text=self.switches[i]["name"])
|
||||||
|
self.switches[i]["label1"].grid(column=0, row=i)
|
||||||
|
self.switches[i]["label2"] = tk.Label(self.switchframe, textvariable=self.switches[i]["stringvar"], relief=Tkconstants.GROOVE, width = 4)
|
||||||
|
self.switches[i]["label2"].grid(column=1, row=i)
|
||||||
|
|
||||||
|
self.dimmerframe = tk.LabelFrame(self, text = "Dimmers", relief=Tkconstants.SUNKEN, bd=1)
|
||||||
|
self.dimmerframe.grid(column=1, row=0)
|
||||||
|
for i in range(4):
|
||||||
|
self.dimmers[i]["stringvar"] = tk.StringVar(value=str(self.dimmers[i]["value"]))
|
||||||
|
self.dimmers[i]["label1"] = tk.Label(self.dimmerframe, text=self.dimmers[i]["name"])
|
||||||
|
self.dimmers[i]["label1"].grid(column=0, row=i)
|
||||||
|
self.dimmers[i]["label2"] = tk.Label(self.dimmerframe, textvariable=self.dimmers[i]["stringvar"], relief=Tkconstants.GROOVE, width = 4)
|
||||||
|
self.dimmers[i]["label2"].grid(column=1, row=i)
|
||||||
|
|
||||||
|
#self.quitButton = tk.Button(self, text='Quit', command=self.quit)
|
||||||
|
#self.quitButton.grid()
|
||||||
|
|
||||||
|
|
||||||
|
def createSwitchMsg(self, switch, seq, stamp):
|
||||||
|
msg = DeviceStatusUpdate()
|
||||||
|
msg.seq = seq
|
||||||
|
msg.device_id = switch["id"]
|
||||||
|
msg.device_type = "core/devices/switch"
|
||||||
|
msg.stamp = stamp
|
||||||
|
|
||||||
|
msg_body = dict()
|
||||||
|
|
||||||
|
msg_body["switch"] = dict()
|
||||||
|
msg_body["switch"]["value"] = switch["value"]
|
||||||
|
|
||||||
|
msg_schema = self.schemaProvider.getTypeSchema("core/devices/switch/status")
|
||||||
|
validator = load(msg_schema, provider=self.schemaProvider)
|
||||||
|
|
||||||
|
validator.validate(msg_body)
|
||||||
|
|
||||||
|
msg.msg_body = json.dumps(msg_body)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def createDimmerMsg(self, dimmer, seq, stamp):
|
||||||
|
msg = DeviceStatusUpdate()
|
||||||
|
msg.seq = seq
|
||||||
|
msg.device_id = dimmer["id"]
|
||||||
|
msg.device_type = "core/devices/dimmer"
|
||||||
|
msg.stamp = stamp
|
||||||
|
|
||||||
|
msg_body = dict()
|
||||||
|
|
||||||
|
msg_body["dimmer"] = dict()
|
||||||
|
msg_body["dimmer"]["value"] = dimmer["value"]
|
||||||
|
|
||||||
|
msg_schema = self.schemaProvider.getTypeSchema("core/devices/dimmer/status")
|
||||||
|
validator = load(msg_schema, provider=self.schemaProvider)
|
||||||
|
validator.validate(msg_body)
|
||||||
|
|
||||||
|
msg.msg_body = json.dumps(msg_body)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def deviceStatusCallback(self):
|
||||||
|
stamp = rospy.get_rostime()
|
||||||
|
for switch in self.switches:
|
||||||
|
self.statusPublisher.publish(self.createSwitchMsg(self.switches[switch], self.msg_sequence, stamp))
|
||||||
|
for dimmer in self.dimmers:
|
||||||
|
self.statusPublisher.publish(self.createDimmerMsg(self.dimmers[dimmer], self.msg_sequence, stamp))
|
||||||
|
self.msg_sequence += 1
|
||||||
|
self.after(10000, self.deviceStatusCallback)
|
||||||
|
|
||||||
|
|
||||||
|
def deviceCmdCallback(self, data):
|
||||||
|
rospy.loginfo(rospy.get_caller_id() + ": I heard %s", str(data))
|
||||||
|
for i in self.switches:
|
||||||
|
if self.switches[i]["id"] == data.device_id:
|
||||||
|
self.deviceSwitchCmdCallback(self.switches[i], data)
|
||||||
|
return
|
||||||
|
for i in self.dimmers:
|
||||||
|
if self.dimmers[i]["id"] == data.device_id:
|
||||||
|
self.deviceDimmerCmdCallback(self.dimmers[i], data)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def deviceSwitchCmdCallback(self, switch, data):
|
||||||
|
msg_body = json.loads(data.msg_body)
|
||||||
|
msg_schema = self.schemaProvider.getTypeSchema("core/devices/switch/command")
|
||||||
|
validator = load(msg_schema, provider=self.schemaProvider)
|
||||||
|
validator.validate(msg_body)
|
||||||
|
|
||||||
|
value = msg_body["switch"]["set"]
|
||||||
|
switch["value"] = bool(value)
|
||||||
|
switch["stringvar"].set(str(value))
|
||||||
|
|
||||||
|
stamp = rospy.get_rostime()
|
||||||
|
self.statusPublisher.publish(self.createSwitchMsg(switch, self.msg_sequence, stamp))
|
||||||
|
self.msg_sequence += 1
|
||||||
|
|
||||||
|
|
||||||
|
def deviceDimmerCmdCallback(self, dimmer, data):
|
||||||
|
print
|
||||||
|
msg_body = json.loads(data.msg_body)
|
||||||
|
msg_schema = self.schemaProvider.getTypeSchema("core/devices/dimmer/command")
|
||||||
|
validator = load(msg_schema, provider=self.schemaProvider)
|
||||||
|
validator.validate(msg_body)
|
||||||
|
value = msg_body["dimmer"]["set"]
|
||||||
|
dimmer["value"] = float(value)
|
||||||
|
dimmer["stringvar"].set(value)
|
||||||
|
|
||||||
|
stamp = rospy.get_rostime()
|
||||||
|
self.statusPublisher.publish(self.createDimmerMsg(dimmer, self.msg_sequence, stamp))
|
||||||
|
self.msg_sequence += 1
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from distutils.core import setup
|
||||||
|
from catkin_pkg.python_setup import generate_distutils_setup
|
||||||
|
|
||||||
|
package_info = generate_distutils_setup(
|
||||||
|
packages=['hos_dummy'],
|
||||||
|
package_dir={'': 'python'},
|
||||||
|
)
|
||||||
|
|
||||||
|
setup(**package_info)
|
||||||
@@ -10,13 +10,13 @@ from hos_core_msgs.msg import DeviceCommand
|
|||||||
from hos_huecontroller.huecontroller import HueController
|
from hos_huecontroller.huecontroller import HueController
|
||||||
|
|
||||||
|
|
||||||
controller = HueController()
|
|
||||||
|
|
||||||
def deviceCmdCallback(data):
|
def deviceCmdCallback(data):
|
||||||
controller.deviceCmdCallback(data)
|
controller.deviceCmdCallback(data)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
try:
|
try:
|
||||||
|
controller = HueController()
|
||||||
rospy.Subscriber(controller.cmd_topic, DeviceCommand, deviceCmdCallback)
|
rospy.Subscriber(controller.cmd_topic, DeviceCommand, deviceCmdCallback)
|
||||||
controller.mainLoop()
|
controller.mainLoop()
|
||||||
except socket.error as e:
|
except socket.error as e:
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
||||||
"title": "Color Capability",
|
|
||||||
"description": "",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"colormode": {
|
|
||||||
"description": "",
|
|
||||||
"type": "string",
|
|
||||||
"persistent": "True",
|
|
||||||
"volatile": "False"
|
|
||||||
},
|
|
||||||
"prop1": {
|
|
||||||
"$ref" : "hos:schema://core/capabilities/switch/command#"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"test" : "bla",
|
|
||||||
"persistent": ["bla1", "bla2"]
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user