For this second example, we will create a more sophisticated server : it will calculate the average temperature and send it.
In the previous, we define many bus in the configuration. This have some limits, in particular if we want to do some operations (like calculating the average temperature) on the values.
So in this example, we will create a new bus which will hold all the sensors and define a new value.
Change to the tutorial directory :
$ cd /opt/janitoo/src/janitoo_tutorial
Open the tutorial2 implementation :
$ vim src/janitoo_tutorial/tutorial2.py
We will import all the needed components, and update their oid to match the new bus oid (tutorial2). For the DHT component, it’s looks like :
from janitoo_raspberry_dht.dht import DHTComponent
...
class AmbianceComponent(DHTComponent):
""" A component for ambiance """
def __init__(self, bus=None, addr=None, **kwargs):
"""
"""
oid = kwargs.pop('oid', 'tutorial2.ambiance')
name = kwargs.pop('name', "Ambiance sensor")
DHTComponent.__init__(self, oid=oid, bus=bus, addr=addr, name=name,
**kwargs)
At first, we will aggregate the needed bus. We don’t need to aggregate the rpibasic bus (which hold the dht component) as it holds no special features. Of course, we would add it without problem.
def __init__(self, **kwargs):
"""
"""
JNTBus.__init__(self, **kwargs)
self.buses = {}
self.buses['gpiobus'] = GpioBus(masters=[self], **kwargs)
self.buses['1wire'] = OnewireBus(masters=[self], **kwargs)
After, we will a new value to propagate the average tempetature :
uuid="{:s}_temperature".format(OID)
self.values[uuid] = self.value_factory['sensor_temperature'](options=self.options, uuid=uuid,
node_uuid=self.uuid,
get_data_cb=self.get_temperature_cb,
help='The average temperature of tutorial. Can be use as a good quality source for a thermostat.',
label='Temp',
)
poll_value = self.values[uuid].create_poll_value(default=300)
self.values[poll_value.uuid] = poll_value
We also define a poll value to this value.
The thread hold the bus :
$ vim src/janitoo_tutorial/thread_tutorial2.py
We will import all the needed components, and update their oid to match the new bus oid (tutorial2). For the DHT component, it’s looks like :
class TutorialThread(JNTBusThread):
"""The basic thread
"""
def init_bus(self):
"""Build the bus
"""
from janitoo_tutorial.tutorial2 import TutorialBus
self.section = OID
self.bus = TutorialBus(options=self.options, oid=self.section, product_name="Raspberry tutorial controller")
Janitoo uses entry-points for defining threads (bus) and components :
entry_points = {
"janitoo.threads": [
"tutorial2 = janitoo_tutorial.thread_tutorial2:make_thread",
],
"janitoo.components": [
"tutorial2.ambiance = janitoo_tutorial.tutorial2:make_ambiance",
"tutorial2.cpu = janitoo_tutorial.tutorial2:make_cpu",
"tutorial2.temperature = janitoo_tutorial.tutorial2:make_temperature",
],
},
The entry-point reference a function in the thread :
def make_thread(options, force=False):
if get_option_autostart(options, OID) == True or force:
return TutorialThread(options)
else:
return None
Or for the component :
def make_ambiance(**kwargs):
return AmbianceComponent(**kwargs)
Open the test configuration file in your favorite editor :
$ vim tests/data/helloworldv2.conf
Like seen in the first tutorial, there is a section for the new bus (thread) :
[tutorial2]
auto_start = True
name = Hello world
location = Rapsberry
components.ambiance = tutorial2.ambiance
components.temperature = tutorial2.temperature
components.cpu = tutorial2.cpu
hadd = 0225/0000
It defines a new bus with a name and a location. We must define the HADD of the controller node associated to the bus (0225/0000). But this bus now holds the 3 components.
Look at the DHT section, it’s similar to the one seen in first tutorial :
[tutorial2__ambiance]
name = Ambiance 1
location = DHT
hadd = 0225/0001
pin_0 = 6
sensor_0 = 11
You’re ready to test your components. Create a test for each component. For example, for the DTH:
$ vim tests/test_components_v2.py
class TestAmbianceComponent(JNTTComponent, JNTTComponentCommon):
"""Test the component
"""
component_name = "tutorial2.ambiance"
And launch it :
$ sudo nosetests -v tests/test_components_v2.py
The result should be :
test_001_component_entry_point (tests.test_components_v2.TestAmbianceComponent) ... ok
test_002_component_oid (tests.test_components_v2.TestAmbianceComponent) ... ok
test_002_component_properties (tests.test_components_v2.TestAmbianceComponent) ... ok
test_001_component_entry_point (tests.test_components_v2.TestCpuComponent) ... ok
test_002_component_oid (tests.test_components_v2.TestCpuComponent) ... ok
test_002_component_properties (tests.test_components_v2.TestCpuComponent) ... ok
test_001_component_entry_point (tests.test_components_v2.TestLedComponent) ... ok
test_002_component_oid (tests.test_components_v2.TestLedComponent) ... ok
test_002_component_properties (tests.test_components_v2.TestLedComponent) ... ok
test_001_component_entry_point (tests.test_components_v2.TestTemperatureComponent) ... ok
test_002_component_oid (tests.test_components_v2.TestTemperatureComponent) ... ok
test_002_component_properties (tests.test_components_v2.TestTemperatureComponent) ... ok
----------------------------------------------------------------------
Ran 12 tests in 6.772s
OK
Test for the tread :
$ vim tests/tests/test_thread_v2.py
class TestTutorialThread(JNTTThreadRun, JNTTThreadRunCommon):
"""Test the thread
"""
thread_name = "tutorial2"
conf_file = "tests/data/janitoo_tutorial2.conf"
And launch it :
$ sudo nosetests -v tests/test_thread_v2.py
The result should be :
test_001_thread_entry_point (tests.test_thread_v2.TestTutorialThread) ... ok
test_011_thread_start_wait_stop (tests.test_thread_v2.TestTutorialThread) ... ok
test_031_cron_hourly (tests.test_thread_v2.TestTutorialThread) ... SKIP: Hourly timer not used for this thread
----------------------------------------------------------------------
Ran 3 tests in 27.107s
OK (SKIP=1)
And the test for the bus :
$ vim tests/tests/test_bus_v2.py
from janitoo_tutorial.tutorial2 import TutorialBus
class TestTutorialBus(JNTTBus, JNTTBusCommon):
"""Test the Bus
"""
oid = 'tutorial2'
bus = TutorialBus
And launch it :
$ sudo nosetests -v tests/test_bus_v2.py
The result should be :
test_001_bus_oid (tests.test_bus_v2.TestTutorialBus) ... ok
test_002_bus_values (tests.test_bus_v2.TestTutorialBus) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.784s
OK
And for the server :
$ vim tests/test_server_v2.py
class TestTutorialServer(JNTTServer, JNTTServerCommon):
"""Test the tutorial server
"""
server_class = PiServer
server_conf = "tests/data/helloworldv2.conf"
hadds = [HADD%(225,0), HADD%(225,1), HADD%(225,2), HADD%(225,3)]
And launch it :
$ sudo nosetests -v tests/test_server_v2.py
The result should be :
test_010_start_heartbeat_stop (tests.test_server_v2.TestTutorialServer) ... ok
test_011_start_reload_stop (tests.test_server_v2.TestTutorialServer) ... ok
test_012_start_reload_threads_stop (tests.test_server_v2.TestTutorialServer) ... ok
test_020_request_broadcast (tests.test_server_v2.TestTutorialServer) ... ok
test_030_wait_for_all_nodes (tests.test_server_v2.TestTutorialServer) ... ok
test_040_server_start_no_error_in_log (tests.test_server_v2.TestTutorialServer) ... ok
----------------------------------------------------------------------
Ran 6 tests in 828.932s
OK
Otherwise you should have a log capture with surely some errors inside.
You can also the whole tests, which whould help you to fix problems :
$ sudo make tests
You can now copy the config file to the config directory:
$ cd /opt/janitoo/etc
$ cp /opt/janitoo/src/janitoo_tutorial/tests/data/helloworldv2.conf .
Launch the server :
$ sudo jnt_raspberry -c /opt/janitoo/etc/helloworldv2.conf start
You can look at the protocol during startup on the spyer terminal.
You can also look at logs. In a new terminal :
$ tail -n 100 -f /opt/janitoo/log/helloworldv2.log
Its time to query ther server. Go to the first terminal and query the network :
$ jnt_query network
You should receive the list of nodes availables on your server :
hadd uuid name location product_type
0225/0000 tutorial2 Hello world Rapsberry Default product type
0225/0002 tutorial2__temperature Temperature Onewire Temperature sensor
0225/0001 tutorial2__ambiance Ambiance 1 DHT Temperature/humidity sensor
0225/0003 tutorial2__cpu CPU Hostsensor Software component
You can also query a node :
$ jnt_query node --hadd 0225/0000
hadd uuid name location product_type
0225/0000 tutorial2 Hello world Rapsberry Default product type
0225/0002 tutorial2__temperature Temperature Onewire Temperature sensor
0225/0001 tutorial2__ambiance Ambiance 1 DHT Temperature/humidity sensor
0225/0003 tutorial2__cpu CPU Hostsensor Software component
Check the config values :
$ jnt_query node --hadd 0225/0000 --vuuid request_info_configs
hadd node_uuid uuid idx data units type genre cmdclass help
0225/0001 tutorial2__ambiance temperature_poll 0 300 seconds 4 3 112 The poll delay of the value
0225/0001 tutorial2__ambiance name 0 Ambiance 1 None 8 3 112 The name of the node
0225/0001 tutorial2__ambiance pin 0 6 None 4 3 112 The pin number on the board
0225/0001 tutorial2__ambiance humidity_poll 0 300 seconds 4 3 112 The poll delay of the value
0225/0001 tutorial2__ambiance location 0 DHT None 8 3 112 The location of the node
0225/0001 tutorial2__ambiance sensor 0 11 None 4 3 112 The sensor type : 11,22,2302
0225/0000 tutorial2 tutorial2_temperature_poll 0 300 seconds 4 3 112 The poll delay of the value
0225/0000 tutorial2 name 0 Hello world None 8 3 112 The name of the node
0225/0000 tutorial2 location 0 Rapsberry None 8 3 112 The location of the node
0225/0003 tutorial2__cpu frequency_poll 0 300 seconds 4 3 112 The poll delay of the value
0225/0003 tutorial2__cpu temperature_poll 0 300 seconds 4 3 112 The poll delay of the value
0225/0003 tutorial2__cpu voltage_poll 0 300 seconds 4 3 112 The poll delay of the value
0225/0003 tutorial2__cpu location 0 Hostsensor None 8 3 112 The location of the node
0225/0003 tutorial2__cpu name 0 CPU None 8 3 112 The name of the node
0225/0002 tutorial2__temperature temperature_poll 0 300 seconds 4 3 112 The poll delay of the value
0225/0002 tutorial2__temperature location 0 Onewire None 8 3 112 The location of the node
0225/0002 tutorial2__temperature hexadd 0 28-00000463b745 None 8 3 112 The hexadecimal address of the DS18B20
0225/0002 tutorial2__temperature name 0 Temperature None 8 3 112 The name of the node
Get the user values :
$ jnt_query node --hadd 0225/0000 --vuuid request_info_users
hadd node_uuid uuid idx data units type genre cmdclass help
0225/0001 tutorial2__ambiance temperature 0 19.0 °C 3 2 49 The temperature
0225/0001 tutorial2__ambiance humidity 0 30.0 % 3 2 49 The humidity
0225/0000 tutorial2 tutorial2_temperature 0 25.6 °C 3 2 49 The average temperature of tutorial. Can be use as a good quality source for a thermostat.
0225/0003 tutorial2__cpu frequency 0 1000 MHz 3 2 49 The frequency of the CPU
0225/0003 tutorial2__cpu voltage 0 1.35 V 3 2 49 The voltage of the CPU
0225/0003 tutorial2__cpu temperature 0 38.5 °C 3 2 49 The temperature of the CPU
0225/0002 tutorial2__temperature temperature 0 19.2 °C 3 2 49 The temperature
$ nice top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3050 root 20 0 59340 13m 4288 S 2,3 2,7 1:30.00 /usr/bin/python /usr/local/bin/jnt_tutorial -c /opt/janitoo/src/janitoo_tutorial/tests/data/helloworldv
We divide the virtual memory by 2. Reserved memory is also less.