...
 
Commits (31)
......@@ -16,3 +16,6 @@ version.h
*.save
.idea/
*.pyc
*.swp
......@@ -142,6 +142,18 @@ log_pkg_found(cppdb "${CPPDB_FOUND}" "" WARNING ", parts of core will not be bui
pkg_search_module(LIBRRD librrd)
log_pkg_found(librrd "${LIBRRD_FOUND}" "${LIBRRD_VERSION}" WARNING ", parts of core will not be built")
find_package(Qpid)
log_pkg_found(qpid "${QPID_FOUND}" "${QPID_VERSION}" STATUS ", QPID communication support will not be built")
set(WITH_QPID ${QPID_FOUND})
find_package(Mosquittopp)
log_pkg_found(mosquittopp "${MOSQUITTOPP_FOUND}" "${MOSQUITTOPP_VERSION}" WARNING ", MQTT communication support will not be built")
set(WITH_MQTT ${MOSQUITTOPP_FOUND})
if(NOT ${MOSQUITTOPP_FOUND} AND NOT ${QPID_FOUND})
message(FATAL_ERROR "Neither mosquittopp nor qpid found. One or both is required")
endif()
if(OS_LINUX)
# used by agosystem
pkg_search_module(LIBPROCPS REQUIRED libprocps)
......@@ -206,10 +218,8 @@ endif()
install(DIRECTORY DESTINATION ${BINDIR})
# add sub directories
option(BUILD_SHARED "Build the agoclient shared library" ON)
if (BUILD_SHARED)
add_subdirectory (shared)
endif()
add_subdirectory (shared)
add_subdirectory (python)
option(BUILD_TESTS "Build the unittests" ON)
if (BUILD_TESTS AND CPPUNIT_FOUND)
......
import json
import os
import threading
import time
import traceback
from collections import namedtuple
import pytest
import logging
try:
import paho.mqtt.client as mqtt
HAS_MQTT = True
except ImportError:
HAS_MQTT = False
@pytest.fixture(scope='session')
def mqttc():
assert HAS_MQTT
#broker = os.environ.get('AGO_BROKER', 'localhost')
#username = os.environ.get('AGO_USERNAME', 'agocontrol')
#password = os.environ.get('AGO_PASSWORD', 'letmein')
mqttc = mqtt.Client(client_id='ago-autotest', clean_session=True)
mqttc.loop_start()
ready_cond = threading.Condition()
def mqtt_on_connect(client, userdata, flags, rc):
#print("MQTT connected, subscibing")
client.subscribe('com.agocontrol/legacy')
def mqtt_on_subscribe(client, userdata, mid, granted_qos):
#print("MQTT subscribed")
ready_cond.acquire()
ready_cond.notify()
ready_cond.release()
mqttc.on_connect = mqtt_on_connect
mqttc.on_subscribe = mqtt_on_subscribe
mqttc.connect('localhost')
ready_cond.acquire()
ready_cond.wait(10)
ready_cond.release()
# print("Setup ready")
yield mqttc
mqttc.disconnect()
mqttc.loop_stop()
@pytest.fixture(scope='function')
def mqtt_transport_adapter(mqttc):
adapter = MqttTransportAdapter(mqttc)
return adapter
MqttTransportMessage = namedtuple('MqttTransportMessage', 'content,subject')
class MqttTransportAdapter:
def __init__(self, mqttc, timeout=10):
self.mqttc = mqttc
def set_handler(self, handler):
self.handler = handler
self.mqttc.on_message = self.on_message
def on_message(self, client, userdata, message):
#print("Got message on ", message.topic, ":", message.payload)
try:
json_payload = json.loads(message.payload)
if 'UT-EXP' not in json_payload['content']:
# Ignore other spurious msgs
#print("Ignoring message")
return
tpm = MqttTransportMessage(json_payload['content'], json_payload.get('subject', None))
rep = self.handler(tpm)
if rep:
logging.info("Got msg %s, replying with %s", (json_payload, rep))
self.mqttc.publish(json_payload['reply-to'], json.dumps(rep))
#else:
#print("Handler called, but no reply")
except:
traceback.print_exc()
def send(self, content, subject):
topic = 'com.agocontrol/legacy'
self.mqttc.publish(topic, payload=json.dumps(dict(content=content, subject=subject)))
def shutdown(self):
self.mqttc.on_message = None
import os
import threading
import time
import pytest
import logging
try:
from qpid.messaging import Connection, Message, Empty, LinkClosed
HAS_QPID = True
except ImportError:
HAS_QPID = False
@pytest.fixture(scope='session')
def qpid_details():
assert HAS_QPID
broker = os.environ.get('AGO_BROKER', 'localhost')
username = os.environ.get('AGO_USERNAME', 'agocontrol')
password = os.environ.get('AGO_PASSWORD', 'letmein')
connection = Connection(broker,
username=username,
password=password,
reconnect=True)
connection.open()
session = connection.session()
details = dict(
connection=connection,
session=session,
sender=session.sender("agocontrol; {create: always, node: {type: topic}}")
)
yield details
connection.close()
@pytest.fixture(scope='function')
def qpid_transport_adapter(qpid_details):
adapter = QpidTransportAdapter(qpid_details['session'])
return adapter
class QpidTransportAdapter(threading.Thread):
"""Simple class which will look for Qpid messages, and
execute a handler fn which the test can use to generate a response.
Only reacts to messages with key 'UT-EXP' in content!
"""
def __init__(self, session, timeout=10):
super(QpidTransportAdapter, self).__init__()
self.session = session
self.receiver = self.session.receiver("agocontrol; {create: always, node: {type: topic}}")
self.sender = self.session.sender("agocontrol; {create: always, node: {type: topic}}")
self.timeout = timeout
def set_handler(self, handler):
self.handler = handler
self.start()
def run(self):
self.stop = False
stop_after = time.time() + self.timeout
while not self.stop and time.time() < stop_after:
try:
msg = self.receiver.fetch(timeout=10)
self.session.acknowledge()
if not 'UT-EXP' in msg.content:
# Ignore other spurious msgs
continue
rep = self.handler(msg)
if rep:
logging.info("Got msg %s, replying with %s", (msg.content, rep))
snd = self.session.sender(msg.reply_to)
snd.send(Message(rep))
except (Empty, LinkClosed):
continue
def send(self, content, subject):
message = Message(content=content, subject=subject)
self.sender.send(message)
def shutdown(self):
self.stop = True
self.receiver.close()
if self.is_alive():
self.join()
import logging
import pytest
# Automatically imports
pytest_plugins = ['testlib.qpid_transport', 'testlib.mqtt_transport']
logging.basicConfig()
# TODO: use pytest-variables instead?
@pytest.fixture
def variables(request):
return dict(transport=request.config.getoption("--transport"))
def pytest_addoption(parser):
parser.addoption(
"--transport", action="store", default="qpid", help="transport to test: qpid or mqtt"
)
@pytest.fixture
def transport_adapter(request, variables):
if variables['transport'] == 'qpid':
adapter = request.getfixturevalue('qpid_transport_adapter')
elif variables['transport'] == 'mqtt':
adapter = request.getfixturevalue('mqtt_transport_adapter')
else:
raise AssertionError('Invalid transport configured')
yield adapter
adapter.shutdown()
import os
import json
import urllib2
import random
import time
RPC_PARSE_ERROR = -32700
RPC_INVALID_REQUEST = -32600
RPC_METHOD_NOT_FOUND = -32601
RPC_INVALID_PARAMS = -32602
RPC_INTERNAL_ERROR = -32603
# -32000 to -32099 impl-defined server errors
RPC_NO_EVENT = -32000
RPC_MESSAGE_ERROR = -32001
RPC_COMMAND_ERROR = -31999
url = os.environ.get('AGO_URL', 'http://localhost:8008')
url_jsonrpc = url + '/jsonrpc'
def bus_message(subject, content, expect_identifier=None, expect_rpc_error_code=None, timeout=None):
"""Send a Agocontrol Bus message via the RPC interface"""
params = {
'content': content,
'subject': subject
}
if timeout is not None:
params['replytimeout'] = timeout
# Give HTTP request a bit more time.
timeout = timeout + 0.5
return jsonrpc_request('message', params, expect_identifier=expect_identifier, expect_rpc_error_code=expect_rpc_error_code, timeout=timeout)
def jsonrpc_request(method, params=None, req_id=None, expect_identifier=None, expect_rpc_error_code=None, timeout=None):
"""Execute a JSON-RPC 2.0 request with the specified method, and specified params
dict. If req_id is None, a random ID number is selected.
Spec: http://www.jsonrpc.org/specification
"""
if req_id is None:
req_id = random.randint(1, 10000)
msg = {'jsonrpc': '2.0',
'id': req_id,
'method': method
}
if params:
msg['params'] = params
req_raw = json.dumps(msg)
http_req = urllib2.Request(url_jsonrpc, req_raw)
if not timeout: timeout = 5
http_rep = urllib2.urlopen(http_req, timeout=timeout)
assert http_rep.code == 200
assert 'application/json' == http_rep.info()['Content-Type']
rep_raw = http_rep.read()
rep_body = json.loads(rep_raw)
assert '2.0' == rep_body['jsonrpc']
assert req_id == rep_body['id']
if expect_rpc_error_code:
assert 'error' in rep_body
assert 'result' not in rep_body
err = rep_body['error']
assert 'code' in err
assert expect_rpc_error_code == err['code']
if expect_identifier:
assert expect_identifier == err['identifier']
else:
assert 'identifier' not in err
else:
assert 'error' not in rep_body
assert 'result' in rep_body
if expect_identifier:
assert expect_identifier == rep_body['result']['identifier']
else:
assert 'identifier' not in rep_body['result']
if not expect_rpc_error_code:
return rep_body['result']
else:
return rep_body['error']
class TestRPC(object):
def test_unknown_command(self):
jsonrpc_request('no-real', expect_rpc_error_code=RPC_METHOD_NOT_FOUND)
def test_bus_message(self, transport_adapter):
def mock(msg):
assert 'command' in msg.content
assert 'some-command' == msg.content['command']
assert 1234 == msg.content['int-param']
return {'_newresponse':True, 'result':{'identifier': 'success', 'data': {'int':4321, 'string':'test'}}}
transport_adapter.set_handler(mock)
rep = bus_message('', {'command':'some-command', 'int-param':1234, 'UT-EXP':True}, expect_identifier='success')
# rep is result from response
assert 4321 == rep['data']['int']
assert 'test' == rep['data']['string']
def test_bus_message_err(self, transport_adapter):
def mock(msg):
assert 'command' in msg.content
assert 'some-err-command' == msg.content['command']
assert 12345 == msg.content['int-param']
return {'_newresponse':True, 'error':{'identifier': 'some.error', 'message': 'err', 'data': {'int':4321, 'string':'test'}}}
transport_adapter.set_handler(mock)
rep = bus_message('', {'command':'some-err-command', 'int-param':12345, 'UT-EXP':True},
expect_identifier='some.error',
expect_rpc_error_code=RPC_COMMAND_ERROR)
# rep is error from response; contains message, code and data.
assert 'some.error' == rep['identifier']
assert 'err' == rep['message']
assert 4321 == rep['data']['int']
assert 'test' == rep['data']['string']
def test_empty_bus_message(self):
jsonrpc_request('message', None, expect_rpc_error_code=RPC_INVALID_PARAMS)
def test_no_reply_timeout(self):
s = time.time()
# Must take at least 0.5s
ret = bus_message('', {'command':'non-existent'},
expect_identifier='error.no.reply',
expect_rpc_error_code=RPC_COMMAND_ERROR, timeout=0.5)
e = time.time()
assert "Timeout" == ret['message']
assert e-s >= 0.5
assert e-s < 1.0 # but quite near 0.5..
def test_inventory(self):
"""Executes an inventory request, assumes agoresolver is alive"""
rep = bus_message('', {'command':'inventory'}, expect_identifier='success')
assert dict == type(rep)
assert rep.get('identifier') == 'success'
assert 'data' in rep
data = rep['data']
assert 'devices' in data
assert 'schema' in data
assert 'rooms' in data
assert 'floorplans' in data
assert 'system' in data
assert 'variables' in data
assert 'environment' in data
def test_get_event_errors(self):
jsonrpc_request('getevent', None, expect_rpc_error_code= RPC_INVALID_PARAMS)
jsonrpc_request('getevent', {}, expect_rpc_error_code=RPC_INVALID_PARAMS)
jsonrpc_request('getevent', {'uuid':'123'}, expect_rpc_error_code=RPC_INVALID_PARAMS)
def test_subscribe(self, transport_adapter):
sub_id = jsonrpc_request('subscribe', None)
assert type(sub_id) in (str,unicode)
err = jsonrpc_request('getevent', {'uuid':sub_id, 'timeout':0}, expect_rpc_error_code=RPC_NO_EVENT)
assert err['message'] == 'No messages available'
# Send a message
transport_adapter.send(content={'test':1, 'notify':True}, subject='event.something.subject')
while True:
res = jsonrpc_request('getevent', {'uuid':sub_id, 'timeout':1})
if res['event'] == 'event.device.announce':
# Ignore announce from other devices.
# Besides that, nothing shall talk on our test network
continue
assert 'notify' in res
assert res['test'] == 1
assert res['event'] =='event.something.subject'
break
jsonrpc_request('unsubscribe', None, expect_rpc_error_code=RPC_INVALID_PARAMS)
jsonrpc_request('unsubscribe', {'uuid':None}, expect_rpc_error_code=RPC_INVALID_PARAMS)
rep = jsonrpc_request('unsubscribe', {'uuid':sub_id})
assert "success" == rep
def test_subscribe_timeout(self):
# Ensure we can do subseccond precision on getevent timeouts
sub_id = jsonrpc_request('subscribe', None)
assert type(sub_id)in (str,unicode)
s = time.time()
err = jsonrpc_request('getevent', {'uuid':sub_id, 'timeout':0.5}, expect_rpc_error_code=RPC_NO_EVENT)
e = time.time()
assert err['message'] == 'No messages available'
assert e-s >= 0.5
assert e-s < 0.6
......@@ -8,4 +8,7 @@
#cmakedefine HAVE_XLOCALE_H @HAVE_XLOCALE_H@
#cmakedefine WITH_MQTT @WITH_MQTT@
#cmakedefine WITH_QPID @WITH_QPID@
#endif
\ No newline at end of file
......@@ -14,11 +14,10 @@ function(CopyFilesFromSource TARGET SOURCE_FILES)
if (NOT IN_SOURCE_BUILD)
add_custom_target(${TARGET} ALL SOURCES ${SOURCE_FILES})
foreach (infile ${SOURCE_FILES})
string(REPLACE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} outfile ${infile})
#message("-- staging for copy: ${CMAKE_CURRENT_SOURCE_DIR}/${infile} -> ${CMAKE_CURRENT_BINARY_DIR}/${outfile}")
#message("-- staging for copy: ${CMAKE_CURRENT_SOURCE_DIR}/${infile} -> ${CMAKE_CURRENT_BINARY_DIR}/${infile}")
add_custom_command(
TARGET ${TARGET}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${infile} ${outfile}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${infile} ${infile}
VERBATIM
)
endforeach()
......
# From https://github.com/romaniucradu/Calculated/blob/master/cmake_modules/FindMosquittopp.cmake
# - Find libmosquitto
# Find the native libmosquitto includes and libraries
#
# MOSQUITTOPP_INCLUDE_DIR - where to find mosquitto.h, etc.
# MOSQUITTOPP_LIBRARIES - List of libraries when using libmosquitto.
# MOSQUITTOPP_FOUND - True if libmosquitto found.
if(MOSQUITTOPP_INCLUDE_DIR)
# Already in cache, be silent
set(MOSQUITTOPP_FIND_QUIETLY TRUE)
endif(MOSQUITTOPP_INCLUDE_DIR)
find_path(MOSQUITTOPP_INCLUDE_DIR mosquitto.h)
find_library(MOSQUITTOPP_LIBRARY NAMES libmosquittopp mosquittopp)
find_library(MOSQUITTO_LIBRARY NAMES libmosquitto mosquitto)
# Handle the QUIETLY and REQUIRED arguments and set MOSQUITTO_FOUND to TRUE if
# all listed variables are TRUE.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MOSQUITTOPP DEFAULT_MSG MOSQUITTOPP_LIBRARY MOSQUITTOPP_INCLUDE_DIR)
if(MOSQUITTOPP_FOUND)
set(MOSQUITTOPP_LIBRARIES ${MOSQUITTOPP_LIBRARY} ${MOSQUITTO_LIBRARY})
else(MOSQUITTOPP_FOUND)
set(MOSQUITTOPP_LIBRARIES)
endif(MOSQUITTOPP_FOUND)
mark_as_advanced(MOSQUITTOPP_INCLUDE_DIR MOSQUITTOPP_LIBRARY)
# Find qpid libraries and headers
#
# QPID_INCLUDE_DIR - where to find qpid/messaging/*.h, etc.
# QPID_LIBRARIES - List of libraries when using qpid.
# QPID_FOUND - True if qpid found.
if(QPID_INCLUDE_DIR)
# Already in cache, be silent
set(QPID_FIND_QUIETLY TRUE)
endif(QPID_INCLUDE_DIR)
find_path(QPID_INCLUDE_DIR qpid/messaging/Connection.h)
find_library(QPID_MESSAGING_LIBRARY NAMES qpidmessaging)
find_library(QPID_TYPES_LIBRARY NAMES qpidtypes)
# Handle the QUIETLY and REQUIRED arguments and set QPID_FOUND to TRUE if
# all listed variables are TRUE.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(QPID DEFAULT_MSG QPID_MESSAGING_LIBRARY QPID_INCLUDE_DIR)
if(QPID_FOUND)
set(QPID_LIBRARIES ${QPID_MESSAGING_LIBRARY} ${QPID_TYPES_LIBRARY})
else(QPID_FOUND)
set(QPID_LIBRARIES)
endif(QPID_FOUND)
mark_as_advanced(QPID_INCLUDE_DIR QPID_LIBRARY)
......@@ -16,6 +16,8 @@ foreach (infile ${INIT_FILES})
endforeach (infile)
CopyFilesFromSource(augeas_lens "agocontrol.aug")
add_subdirectory (conf.d)
add_subdirectory (schema.d)
add_subdirectory (sysvinit)
......
cmake_minimum_required (VERSION 3.0)
file (GLOB CONFD_FILES *.in)
file (GLOB CONFD_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.in)
foreach (infile ${CONFD_FILES})
string(REGEX REPLACE ".in$" "" outfile ${infile})
string(REGEX REPLACE ".*/" "" outfile ${outfile})
configure_file(
"${infile}"
"${CMAKE_CURRENT_BINARY_DIR}/${outfile}"
@ONLY
)
LIST(APPEND CONFD_FILES_DONE ${CMAKE_CURRENT_BINARY_DIR}/${outfile})
LIST(APPEND CONFD_FILES_DONE ${outfile})
endforeach (infile)
file (GLOB CONFD_FILES *.conf)
install (FILES ${CONFD_FILES_DONE} ${CONFD_FILES} DESTINATION ${CONFDIR}/conf.d)
file (GLOB CONFD_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.conf)
CopyFilesFromSource(conf_files "${CONFD_FILES}")
InstallFiles(${CONFDIR}/conf.d "${CONFD_FILES_DONE};${CONFD_FILES}")
[system]
uuid=00000000-0000-0000-000000000000
# mqtt or qpid
messaging=qpid
# address to broker, hostname[:port]
broker=localhost
# when you change username and/or password, you also need to adjust the qpid sasl db to reflect the change
username=agocontrol
password=letmein
units=SI
# Please see http://wiki.agocontrol.com/index.php/Logging for more details on Logging
......@@ -11,3 +19,28 @@ units=SI
log_method=syslog
# log levels: TRACE, DEBUG, INFO, WARNING, ERROR, FATAL
log_level=INFO
[loggers]
# The main log_level controls the overall logging level.
# It is then possible to limit different loggers (python) / channels (C++) to a higher level.
# For example, if log_level is set to INFO, nothing lower than INFO will be logged,
# even if a specific logger is set to TRACE.
# Names are shared between both python & C++ implementations (where applicable).
# The low-level qpid python library is very verbose, so do not log anything lower
# than INFO from that library:
qpid=INFO
# Same goes for low-level mqtt library, both on C++ and Python. Cap it to INFO.
mqtt=INFO
# The following are internal application logging in the AgoClient library
# transport is the abstraction of the MQTT/QPID connectivity, and only deals with simple messaging.
transport = TRACE
# connection is a higher-level interface between each application and the transport
connection = TRACE
# This is the "main" logger for C++, if no specific one is used. It is also the default for all applications.
app = TRACE
......@@ -19,7 +19,7 @@ install (DIRECTORY DESTINATION ${CONFDIR}/maps)
install (DIRECTORY DESTINATION ${CONFDIR}/lua)
OPTION(BUILD_CORE_drain "Build agodrain" ON)
if (BUILD_CORE_drain)
if (WITH_QPID AND BUILD_CORE_drain)
add_subdirectory (drain)
endif()
......
......@@ -2,6 +2,7 @@ cmake_minimum_required (VERSION 3.0)
set (DRAIN_LIBRARIES
agoclient
${QPID_LIBRARIES}
)
# add the executable
......
......@@ -21,7 +21,7 @@ private:
qpid::messaging::Connection *connection;
// Override, we do not use a AgoConnection in drain
void setupAgoConnection() { }
bool setupAgoConnection(boost::unique_lock<boost::mutex> &lock) { return true; }
void doShutdown() ;
int appMain();
......
#!/usr/bin/env python
from __future__ import print_function
#Returns all or specified directory structure
#@params get: all|plugins|configs|helps|supported
......@@ -30,7 +31,7 @@ def loadMetadatasInDir(d):
items[obj["dir"]] = obj
except Exception as error:
pass
for key in sorted(items.iterkeys()):
for key in sorted(items.keys()):
out.append(items[key])
return out
......@@ -83,9 +84,9 @@ try:
except Exception as e:
#TODO add message to agolog
pass
result['error'] = str(e)
#send output
print "Content-type: application/json\n"
print json.dumps(result)
print("Content-type: application/json\n")
print(json.dumps(result))
#!/usr/bin/env python
from __future__ import print_function
import os
import sys
......@@ -142,6 +144,6 @@ except Exception as e:
pass
#send output
print "Content-type: application/json\n"
print json.dumps(result)
print("Content-type: application/json\n")
print(json.dumps(result))
This diff is collapsed.
......@@ -30,7 +30,6 @@ opt/agocontrol/bin/agoscenario
opt/agocontrol/bin/agoevent
opt/agocontrol/bin/agolua
opt/agocontrol/bin/myavahi.py
opt/agocontrol/bin/agodrain
opt/agocontrol/bin/messagesend
opt/agocontrol/bin/agotimer
opt/agocontrol/bin/agorpc
......
......@@ -2,13 +2,13 @@ Source: agocontrol
Maintainer: Harald Klein <hari@vt100.at>
Section: misc
Priority: optional
Build-Depends: debhelper (>= 8), libola-dev (>= 0.9.1) | ola-dev, libprocps3-dev (>= 2:3.3.9) | libprocps0-dev (>= 1:3.1.11), libyaml-cpp0.3-dev (<< 0.4) | libyaml-cpp-dev (<< 0.5), python, libqpidmessaging2-dev, libqpidtypes1-dev, libqpidcommon2-dev, libudev-dev, libqpidclient2-dev, uuid-dev, libopenzwave1.3-dev, libtinyxml2-dev, libsqlite3-dev, libi2c-dev, libssl-dev, libboost-dev, intltool, libboost-date-time-dev,realpath,libcurl4-openssl-dev,libhdate-dev,liblua5.2-dev,knxd-dev (>= 0.10.9) | libeibclient-dev (<= 0.0.5), libboost-regex-dev, libaugeas-dev, librrd-dev, cmake, libboost-filesystem-dev, libboost-system-dev, libboost-thread-dev, libboost-program-options-dev, lsb-release, libopencv-dev, libopencv-core-dev, libopencv-imgproc-dev, libopencv-objdetect-dev, libcppdb-dev, libopencv-highgui-dev, libprotobuf9
Build-Depends: debhelper (>= 8), libola-dev (>= 0.9.1) | ola-dev, libprocps3-dev (>= 2:3.3.9) | libprocps0-dev (>= 1:3.1.11), libyaml-cpp0.3-dev (<< 0.4) | libyaml-cpp-dev (<< 0.5), python, libudev-dev, uuid-dev, libopenzwave1.3-dev, libtinyxml2-dev, libsqlite3-dev, libi2c-dev, libssl-dev, libboost-dev, intltool, libboost-date-time-dev,realpath,libcurl4-openssl-dev,libhdate-dev,liblua5.2-dev,knxd-dev (>= 0.10.9) | libeibclient-dev (<= 0.0.5), libboost-regex-dev, libaugeas-dev, librrd-dev, cmake, libboost-filesystem-dev, libboost-system-dev, libboost-thread-dev, libboost-program-options-dev, lsb-release, libopencv-dev, libopencv-core-dev, libopencv-imgproc-dev, libopencv-objdetect-dev, libcppdb-dev, libopencv-highgui-dev, libprotobuf9
Build-Conflicts: libopenzwave1.0-dev
Standards-Version: 3.9.2
Package: agocontrol
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, ${dist:Depends}, python, uuid-runtime, sqlite3, python-pysqlite2, libqpidmessaging2, libqpidtypes1, sasl2-bin, libsasl2-2, libsasl2-modules, qpidd, libsqlite3-0, libagoclient1.0, python-agoclient, libssl-dev, python-nss, libhdate1, python-dbus, librrd4, procps, libcppdb0, libcppdb-sqlite3-0
Depends: ${shlibs:Depends}, ${misc:Depends}, ${dist:Depends}, python, uuid-runtime, sqlite3, python-pysqlite2, sasl2-bin, libsasl2-2, libsasl2-modules, libsqlite3-0, libagoclient1.0, python-agoclient, libssl-dev, python-nss, libhdate1, python-dbus, librrd4, procps, libcppdb0, libcppdb-sqlite3-0
Description: automation system
Package: agocontrol-dbg
......@@ -21,7 +21,7 @@ Description: debug info for agocontrol
Package: libagoclient1.0
Section: libs
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libqpidmessaging2, libqpidtypes1, libqpidclient2, libqpidcommon2, libuuid1, libaugeas0
Depends: ${shlibs:Depends}, ${misc:Depends}, libuuid1, libaugeas0
Description: client routines and utility functions for ago control device interfaces
Package: libagoclient1.0-dev
......@@ -30,6 +30,18 @@ Depends: ${misc:Depends}, libagoclient1.0
Architecture: any
Description: Development header files for the agocontrol client library
Package: libagotransport-mqtt1.0
Section: libs
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libuuid1, libmosquittopp
Description: agoclient support for MQTT backend transport
Package: libagotransport-qpid1.0
Section: libs
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libuuid1, libqpidmessaging2, libqpidtypes1, libqpidclient2, libqpidcommon2, qpidd, libagoclient1.0
Description: agoclient support for Qpid backend transport
Package: python-agoclient
Section: libs
Architecture: all
......
/usr/lib/libagoclient.so.1 /usr/lib/libagoclient.so
/usr/lib/libagohttp.so.1 /usr/lib/libagohttp.so
usr/lib/libagoclient.so.1
usr/lib/libagohttp.so.1
usr/lib/libagocore.so.1
/usr/lib/libagoclient.so.1 /usr/lib/libagoclient.so.1.0
/usr/lib/libagohttp.so.1 /usr/lib/libagohttp.so.1.0
/usr/lib/libagocore.so.1 /usr/lib/libagocore.so.1.0
usr/lib/libagotransport-mqtt.so.1
/usr/lib/libagotransport-mqtt.so.1 /usr/lib/libagotransport-mqtt.so.1.0
\ No newline at end of file
usr/lib/libagotransport-qpid.so.1
opt/agocontrol/bin/agodrain
/usr/lib/libagotransport-qpid.so.1 /usr/lib/libagotransport-qpid.so.1.0
\ No newline at end of file
......@@ -19,5 +19,9 @@ override_dh_auto_configure:
override_dh_auto_build:
dh_auto_build --parallel
# Default runs make test which is very silent in what fails
override_dh_auto_test:
$(MAKE) -j1 check
%:
dh $@ --with python2
......@@ -6,28 +6,29 @@ import time
import logging
import agoclient
from agoclient import agoproto
class AgoSimulator(agoclient.AgoApp):
def message_handler(self, internalid, content):
if "command" in content:
if content["command"] == "on":
print "switching on: " + internalid
print("switching on: " + internalid)
self.connection.emit_event(internalid, "event.device.statechanged", 255, "")
elif content["command"] == "off":
print "switching off: " + internalid
print("switching off: " + internalid)
self.connection.emit_event(internalid, "event.device.statechanged", 0, "")
elif content["command"] == "push":
print "push button: " + internalid
print("push button: " + internalid)
elif content['command'] == 'setlevel':
if 'level' in content:
print "device level changed", content["level"]
print("device level changed", content["level"])
self.connection.emit_event(internalid, "event.device.statechanged", content["level"], "")
else:
return self.connection.response_unknown_command()
return agoproto.response_unknown_command()
return self.connection.response_success()
return agoproto.response_success()
else:
return self.connection.response_bad_parameters()
return agoproto.response_bad_parameters()
def app_cmd_line_options(self, parser):
......@@ -85,11 +86,11 @@ class TestEvent(threading.Thread):
hum = random.randint(20, 75) + random.randint(0,90)/100.0
log.debug("Sending enviromnet changes on sensor 126 (%.2f dgr C, %.2f %% humidity)",
temp, hum)
self.connection.emit_event("126", "event.environment.temperaturechanged", temp, "degC");
self.connection.emit_event("126", "event.environment.humiditychanged", hum, "percent");
self.app.connection.emit_event("126", "event.environment.temperaturechanged", temp, "degC")
self.app.connection.emit_event("126", "event.environment.humiditychanged", hum, "percent")
log.debug("Sending sensortriggered for internal-ID 125, level %d", level)
self.connection.emit_event("125", "event.security.sensortriggered", level, "")
self.app.connection.emit_event("125", "event.security.sensortriggered", level, "")
if (level == 0):
level = 255
......
This diff is collapsed.
This diff is collapsed.
......@@ -194,7 +194,7 @@ class PullStatus(threading.Thread):
else:
self.log.error('PullStatus: Could not get status from light')
except TypeError as e:
self.log.error("PullStatus: Exception occurred in background thread. {}".format(e.message))
self.log.error("PullStatus: Exception occurred in background thread. {}".format(str(e)))
time.sleep(float(self.PollDelay)) # TODO: Calculate ((60-n)/NoDevices)/60
if __name__ == "__main__":
......
This diff is collapsed.
......@@ -8,6 +8,7 @@
#
import agoclient
from agoclient import agoproto
import urllib2
import base64
import picamera
......@@ -33,7 +34,7 @@ def messageHandler(internalid, content):
camera.capture(stream, format='jpeg')
frame = stream.getvalue()
return client.response_success({'image':buffer(base64.b64encode(frame))})
return agoproto.response_success({'image':buffer(base64.b64encode(frame))})
client.add_handler(messageHandler)
......
......@@ -5,6 +5,7 @@
import sys
import agoclient
from agoclient import agoproto
import pylmsserver
import pylmsplaylist
import pylmslibrary
......@@ -199,7 +200,7 @@ def messageHandler(internalid, content):
#check parameters
if not content.has_key("command"):
logging.error('No command specified in content')
return client.response_unknown_command(message='No command specified')
return agoproto.response_unknown_command(message='No command specified')
if internalid==host:
......@@ -208,27 +209,27 @@ def messageHandler(internalid, content):
logging.info("Command ALLON: %s" % internalid)
for player in getPlayers():
player.on()
return client.response_success()
return agoproto.response_success()
elif content["command"]=="alloff":
logging.info("Command ALLOFF: %s" % internalid)
for player in getPlayers():
player.off()
return client.response_success()
return agoproto.response_success()
elif content["command"]=="displaymessage":
if content.has_key('line1') and content.has_key('line2') and content.has_key('duration'):
logging.info("Command DISPLAYMESSAGE: %s" % internalid)
for player in getPlayers():
player.display(content['line1'], content['line2'], content['duration'])
return client.response_success()
return agoproto.response_success()
else:
logging.error('Missing parameters to command DISPLAYMESSAGE')
return client.response_missing_parameters(data={'command': 'displaymessage', 'params': ['line1', 'line2', 'duration']})
return agoproto.response_missing_parameters(data={'command': 'displaymessage', 'params': ['line1', 'line2', 'duration']})
#unhandled command
logging.warn('Unhandled server command')
return client.response_unknown_command(message='Unhandled server command', data=content["command"])
return agoproto.response_unknown_command(message='Unhandled server command', data=content["command"])
else:
......@@ -238,69 +239,69 @@ def messageHandler(internalid, content):
logging.info('Found player: %s' % player)
if not player:
logging.error('Player %s not found!' % internalid)
return client.response_failed('Player "%s" not found!' % internalid)
return agoproto.response_failed('Player "%s" not found!' % internalid)
if content["command"] == "on":
logging.info("Command ON: %s" % internalid)
player.on()
return client.response_success()
return agoproto.response_success()
elif content["command"] == "off":
logging.info("Command OFF: %s" % internalid)
player.off()
return client.response_success()
return agoproto.response_success()
elif content["command"] == "play":
logging.info("Command PLAY: %s" % internalid)
player.play()
return client.response_success()
return agoproto.response_success()
elif content["command"] == "pause":
logging.info("Command PAUSE: %s" % internalid)
player.pause()
return client.response_success()
return agoproto.response_success()
elif content["command"] == "stop":
logging.info("Command STOP: %s" % internalid)
player.stop()
return client.response_success()
return agoproto.response_success()
elif content["command"] == "next":
logging.info("Command NEXT: %s" % internalid)
player.next()
return client.response_success()
return agoproto.response_success()
elif content["command"] == "previous":
logging.info("Command PREVIOUS: %s" % internalid)
player.prev()
return client.response_success()
return agoproto.response_success()
elif content["command"] == "setvolume":
logging.info("Command SETVOLUME: %s" % internalid)
if content.has_key('volume'):
player.set_volume(content['volume'])
return client.response_success()
return agoproto.response_success()
else:
logging.error('Missing parameter "volume" to command SETVOLUME')
return client.response_missing_parameters(data={'command': 'setvolume', 'params': ['volume']})
return agoproto.response_missing_parameters(data={'command': 'setvolume', 'params': ['volume']})
elif content["command"] == "displaymessage":
if content.has_key('line1') and content.has_key('line2') and content.has_key('duration'):
logging.info("Command DISPLAYMESSAGE: %s" % internalid)
player.display(content['line1'], content['line2'], content['duration'])
return client.response_success()
return agoproto.response_success()
else:
logging.error('Missing parameters to command DISPLAYMESSAGE')
return client.response_missing_parameters(data={'command': 'displaymessage', 'params': ['line1', 'line2', 'duration']})
return agoproto.response_missing_parameters(data={'command': 'displaymessage', 'params': ['line1', 'line2', 'duration']})
elif content["command"] == "mediainfos":
infos = get_media_infos(internalid, None)
logging.info(infos)
return client.response_success(infos)
return agoproto.response_success(infos)
#unhandled device command
logging.warn('Unhandled device command')
return client.response_unknown_command(message='Unhandled device command', data=content["command"])
return agoproto.response_unknown_command(message='Unhandled device command', data=content["command"])
#init
......
#!/usr/bin/python
from __future__ import print_function
import time
import agoclient
from agoclient import agoproto
AGO_TELLSTICK_VERSION = '0.0.91'
############################################
......@@ -32,16 +35,16 @@ class AgoTellstick(agoclient.AgoApp):
self.log.trace("rescode = %s", resCode)
# res = self.tellstick.getErrorString(resCode)
self.log.error("Failed to turn on device, res=%s", resCode)
return self.connection.response_failed("Failed to turn on device (%s)" % resCode)
return agoproto.response_failed("Failed to turn on device (%s)" % resCode)
else:
self.connection.emit_event(internalid, "event.device.statechanged", 255, "")
self.log.debug("Turning on device: %s res=%s", internalid, resCode)
return self.connection.response_success()
return agoproto.response_success()
# Allon - TODO: will require changes in schema.yaml + somewhere else too
if content["command"] == "allon":
return self.connection.response_unknown_command()
return agoproto.response_unknown_command()
# Off
if content["command"] == "off":
......@@ -49,13 +52,13 @@ class AgoTellstick(agoclient.AgoApp):
if resCode != 'success': # 0:
# res = self.tellstick.getErrorString(resCode)
self.log.error("Failed to turn off device, res=%s", resCode)
return self.connection.response_failed("Failed to turn off device (%s)" % resCode)
return agoproto.response_failed("Failed to turn off device (%s)" % resCode)
else:
# res = 'Success'
self.connection.emit_event(internalid, "event.device.statechanged", 0, "")
self.log.debug("Turning off device: %s res=%s", internalid, resCode)
return self.connection.response_success()
return agoproto.response_success()
# Setlevel for dimmer
if content["command"] == "setlevel":
......@@ -63,17 +66,17 @@ class AgoTellstick(agoclient.AgoApp):
255 * int(content["level"])) / 100) # Different scales: aGo use 0-100, Tellstick use 0-255
if resCode != 'success': # 0:
self.log.error("Failed dimming device, res=%s", resCode)
return self.connection.response_failed("Failed to dim device (%s)" % resCode)
return agoproto.response_failed("Failed to dim device (%s)" % resCode)
else:
# res = 'Success'
self.connection.emit_event(internalid, "event.device.statechanged", content["level"], "")
self.log.debug("Dimming device=%s res=%s level=%s", internalid, resCode, str(content["level"]))
return self.connection.response_success()
return agoproto.response_success()
return self.connection.response_unknown_command()
return agoproto.response_unknown_command()
return self.connection.response_missing_parameters()
return agoproto.response_missing_parameters()
# Event handlers for device and sensor events
# This method is a call-back, triggered when there is a device event
......@@ -194,7 +197,7 @@ class AgoTellstick(agoclient.AgoApp):
def listNewSensors(self):
sensors = self.tellstick.listSensors()
self.log.debug("listSensors returned %d items", len(sensors))
for id, value in sensors.iteritems():
for id, value in sensors.items():
self.log.trace("listNewSensors: devId: %s ", str(id))
if not value["new"]:
continue
......@@ -311,7 +314,7 @@ class AgoTellstick(agoclient.AgoApp):
from tellstickduo import tellstickduo
self.tellstick = tellstickduo(self)
self.log.debug("Stick: Defaulting to Tellstick Duo")
except OSError, e:
except OSError as e:
self.log.error("Failed to load Tellstick stick version code: %s", e)
raise agoclient.agoapp.StartupError()
......@@ -383,7 +386,7 @@ class AgoTellstick(agoclient.AgoApp):
def listNewDevices(self):
switches = self.tellstick.listSwitches()
for devId, dev in switches.iteritems():
for devId, dev in switches.items():
model = dev["model"]
name = dev["name"]
......
#!/usr/bin/python
from __future__ import print_function
# Filter class, used to store a series of samples and determine if
# a new sample is noise or real sample before adding it to the series
......@@ -60,8 +61,8 @@ class sampleseries():
def load(self):
self.samples = [3.3, 3.4, 3.5, 3.6, 3.5, 3.6, 3.5, 3.6, 3.5, 3.4, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 3.9,
4.0]
print self.samples
print ("len of samples=" + str(self.samples.__len__()))
print(self.samples)
print("len of samples=" + str(self.samples.__len__()))
self.times = [datetime.fromtimestamp(mktime(time.strptime("16 Feb 07 00:56", "%y %b %d %H:%M"))),
datetime.fromtimestamp(mktime(time.strptime("16 Feb 07 01:00", "%y %b %d %H:%M"))),
......@@ -84,11 +85,11 @@ class sampleseries():
datetime.fromtimestamp(mktime(time.strptime("16 Feb 07 04:04", "%y %b %d %H:%M"))),
datetime.fromtimestamp(mktime(time.strptime("16 Feb 07 04:08", "%y %b %d %H:%M")))]
self.createT(self.samples, self.times)
print self.samples2
print self.samples2.__len__()
print(self.samples2)
print(self.samples2.__len__())
# print self.times
print ("len of times=" + str(self.times.__len__()))
print("len of times=" + str(self.times.__len__()))
def createT(self, samples, times):
for x in range(0, times.__len__()):
......@@ -101,12 +102,12 @@ class sampleseries():
self.samples.append(sample)
self.times.append(tm if tm is not None else now)
print ("Now=" + str(now) + " sample=" + str(sample))
print(("Now=" + str(now) + " sample=" + str(sample)))
def removeold(self):
print ("len of samples=" + str(self.samples.__len__()))
print("len of samples=" + str(self.samples.__len__()))
if self.samples.__len__() >= self.maxitems:
print "maxitems reached"
print("maxitems reached")
# find oldest, remove it
def avg(self):
......@@ -129,11 +130,11 @@ if __name__ == "__main__":
# 1/31/2016 4:10 AM 22.4
ret = a.test(22.4, datetime.fromtimestamp(mktime(time.strptime("16 Feb 07 04:10", "%y %b %d %H:%M"))))
print "ret="
print ret
print("ret=")
print(ret)
x = a.times[1] - a.times[0]
print x
print(x)
a.insert(1.0, datetime.fromtimestamp(mktime(time.strptime("16 Feb 07 04:10", "%y %b %d %H:%M"))))
# a.insert(1.1)
......@@ -141,7 +142,7 @@ if __name__ == "__main__":
# a.insert(1.1)
# a.insert(-1.1)
print "avg=" + str(a.avg())
print("avg=" + str(a.avg()))
# print a.times
# print ("len of times=" + str(a.times.__len__()))
......
This diff is collapsed.
from __future__ import print_function
import sys, getopt, httplib, urllib, json, os
import logging, syslog
import oauth.oauth as oauth
......@@ -7,22 +9,22 @@ def info (text):
logging.info (text)
syslog.syslog(syslog.LOG_INFO, text)
if debug:
print "INF " + text + "\n"
print("INF " + text + "\n")
def debug (text):
logging.debug (text)
syslog.syslog(syslog.LOG_DEBUG, text)
if debug:
print "DBG " + text + "\n"
print("DBG " + text + "\n")
def error (text):
logging.error(text)
syslog.syslog(syslog.LOG_ERR, text)
if debug:
print "ERR " + text + "\n"
print("ERR " + text + "\n")
def warning(text):
logging.warning (text)
syslog.syslog(syslog.LOG_WARNING, text)
if debug:
print "WRN " + text + "\n"
print("WRN " + text + "\n")
class LogErr:
def write(self, data):
......@@ -55,13 +57,13 @@ def requestToken():
consumer = oauth.OAuthConsumer(PUBLIC_KEY, PRIVATE_KEY)
request = oauth.OAuthRequest.from_consumer_and_token(consumer, http_url='http://api.telldus.com/oauth/requestToken')
request.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(), consumer, None)
conn = httplib.HTTPConnection('api.telldus.com:80')
conn = http.client.HTTPConnection('api.telldus.com:80')
conn.request(request.http_method, '/oauth/requestToken', headers=request.to_header())
resp = conn.getresponse().read()
token = oauth.OAuthToken.from_string(resp)
print 'Open the following url in your webbrowser:\nhttp://api.telldus.com/oauth/authorize?oauth_token=%s\n' % token.key
print 'After logging in and accepting to use this application run:\n%s --authenticate' % (sys.argv[0])
print('Open the following url in your webbrowser:\nhttp://api.telldus.com/oauth/authorize?oauth_token=%s\n' % token.key)
print('After logging in and accepting to use this application run:\n%s --authenticate' % (sys.argv[0]))
config['telldus']['requestToken'] = str(token.key)
config['telldus']['requestTokenSecret'] = str(token.secret)
saveConfig()
......@@ -77,14 +79,14 @@ def getAccessToken():
resp = conn.getresponse()
if resp.status != 200:
print 'Error retreiving access token, the server replied:\n%s' % resp.read()
print('Error retreiving access token, the server replied:\n%s' % resp.read())
return
token = oauth.OAuthToken.from_string(resp.read())
config['telldus']['requestToken'] = None
config['telldus']['requestTokenSecret'] = None
config['telldus']['token'] = str(token.key)
config['telldus']['tokenSecret'] = str(token.secret)
print 'Authentication successful, you can now use your Tellstick Net with aGo control'
print('Authentication successful, you can now use your Tellstick Net with aGo control')
saveConfig()
def authenticate():
......
......@@ -140,7 +140,7 @@ class tellstickduo(tellstickbase):
sensors = td.listSensors()
if len(sensors) != 0:
for id, value in sensors.iteritems():
for id, value in sensors.items():
self.log.trace("listSensors: devId: %s ", str(id))
if id not in self.ignoreDevices:
......
......@@ -15,6 +15,7 @@ __status__ = "Experimental"
__version__ = AGO_TELLSTICK_VERSION
############################################
from __future__ import print_function
from tellstickbase import tellstickbase
import sys, getopt, httplib, urllib, json, os, thread, time
import oauth.oauth as oauth
......@@ -89,7 +90,7 @@ class tellsticknet(tellstickbase):
if ('error' in response):
name = ''
retString = response['error']
print ("retString=" + retString)
print("retString=" + retString)
else:
name = response['name']
self.names[devId] = response['name']
......@@ -126,7 +127,7 @@ class tellsticknet(tellstickbase):
if ('error' in response):
model = ''
retString = response['error']
print ("retString=" + retString)
print("retString=" +