Skip to content

Commit ab3bdb9

Browse files
author
Lukas Steinert
committed
remake from private repo for upstream
Core ESP2 parts contributed wich stayed untouched compared to my local stuff. Other examples got stripped down and commited as-is as a usage reference and/or snippet lib for other people.
1 parent 839b4ab commit ab3bdb9

10 files changed

+1333
-3
lines changed
+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# -*- encoding: utf-8 -*-
2+
from __future__ import print_function, unicode_literals, division, absolute_import
3+
import logging
4+
5+
import threading
6+
try:
7+
import queue
8+
except ImportError:
9+
import Queue as queue
10+
from enocean.protocol.packet import Packet
11+
from enocean.protocol.constants import PACKET, PARSE_RESULT, RETURN_CODE
12+
13+
14+
class ESP2Communicator(threading.Thread):
15+
'''
16+
Communicator base-class for EnOcean.
17+
Not to be used directly, only serves as base class for SerialCommunicator etc.
18+
'''
19+
logger = logging.getLogger('enocean.communicators.ESP2Communicator')
20+
21+
def __init__(self, callback=None, teach_in=True):
22+
super(ESP2Communicator, self).__init__()
23+
# Create an event to stop the thread
24+
self._stop_flag = threading.Event()
25+
# Input buffer
26+
self._buffer = []
27+
# Setup packet queues
28+
self.transmit = queue.Queue()
29+
self.receive = queue.Queue()
30+
# Set the callback method
31+
self.__callback = callback
32+
# Internal variable for the Base ID of the module.
33+
self._base_id = None
34+
# Should new messages be learned automatically? Defaults to True.
35+
# TODO: Not sure if we should use CO_WR_LEARNMODE??
36+
self.teach_in = teach_in
37+
38+
def _get_from_send_queue(self):
39+
''' Get message from send queue, if one exists '''
40+
try:
41+
packet = self.transmit.get(block=False)
42+
#self.logger.info('Sending packet')
43+
#self.logger.debug(packet)
44+
return packet
45+
except queue.Empty:
46+
pass
47+
return None
48+
49+
def send(self, packet):
50+
if not isinstance(packet, Packet):
51+
self.logger.error('Object to send must be an instance of Packet')
52+
return False
53+
self.transmit.put(packet)
54+
return True
55+
56+
def stop(self):
57+
self._stop_flag.set()
58+
59+
def parse(self):
60+
''' Parses messages and puts them to receive queue '''
61+
# Loop while we get new messages
62+
while True:
63+
status, self._buffer, packet = Packet.parse_msg_ESP2(self._buffer, communicator=self)
64+
# If message is incomplete -> break the loop
65+
if status == PARSE_RESULT.INCOMPLETE:
66+
return status
67+
68+
# If message is OK, add it to receive queue or send to the callback method
69+
if status == PARSE_RESULT.OK and packet:
70+
if self.__callback is None:
71+
self.receive.put(packet)
72+
else:
73+
self.__callback(packet)
74+
#self.logger.debug(packet)
75+
76+
@property
77+
def base_id(self):
78+
''' Fetches Base ID from the transmitter, if required. Otherwise returns the currently set Base ID. '''
79+
# If base id is already set, return it.
80+
if self._base_id is not None:
81+
return self._base_id
82+
83+
# Send COMMON_COMMAND 0x08, CO_RD_IDBASE request to the module
84+
self.send(Packet(PACKET.COMMON_COMMAND, data=[0x08]))
85+
# Loop over 10 times, to make sure we catch the response.
86+
# Thanks to timeout, shouldn't take more than a second.
87+
# Unfortunately, all other messages received during this time are ignored.
88+
for i in range(0, 10):
89+
try:
90+
packet = self.receive.get(block=True, timeout=0.1)
91+
# We're only interested in responses to the request in question.
92+
if packet.packet_type == PACKET.RESPONSE and packet.response == RETURN_CODE.OK and len(packet.response_data) == 4:
93+
# Base ID is set in the response data.
94+
self._base_id = packet.response_data
95+
# Put packet back to the Queue, so the user can also react to it if required...
96+
self.receive.put(packet)
97+
break
98+
# Put other packets back to the Queue.
99+
self.receive.put(packet)
100+
except queue.Empty:
101+
continue
102+
# Return the current Base ID (might be None).
103+
return self._base_id
104+
105+
@base_id.setter
106+
def base_id(self, base_id):
107+
''' Sets the Base ID manually, only for testing purposes. '''
108+
self._base_id = base_id
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# -*- encoding: utf-8 -*-
2+
from __future__ import print_function, unicode_literals, division, absolute_import
3+
import logging
4+
import serial
5+
import time
6+
7+
from enocean.communicators.ESP2communicator import ESP2Communicator
8+
9+
10+
class ESP2SerialCommunicator(ESP2Communicator):
11+
''' Serial port communicator class for EnOcean radio '''
12+
logger = logging.getLogger('enocean.communicators.ESP2SerialCommunicator')
13+
14+
def __init__(self, port='/dev/ttyS0', callback=None):
15+
super(ESP2SerialCommunicator, self).__init__(callback)
16+
# Initialize serial port
17+
self.__ser = serial.Serial(port, 57600, timeout=0.1)
18+
19+
def run(self):
20+
self.logger.info('SerialCommunicator started')
21+
while not self._stop_flag.is_set():
22+
# If there's messages in transmit queue
23+
# send them
24+
while True:
25+
packet = self._get_from_send_queue()
26+
if not packet:
27+
break
28+
try:
29+
self.__ser.write(bytearray(packet.build_ESP2()))
30+
except serial.SerialException:
31+
self.stop()
32+
33+
# Read chars from serial port as hex numbers
34+
try:
35+
self._buffer.extend(bytearray(self.__ser.read(16)))
36+
except serial.SerialException:
37+
self.logger.error('Serial port exception! (device disconnected or multiple access on port?)')
38+
self.stop()
39+
self.parse()
40+
time.sleep(0)
41+
42+
self.__ser.close()
43+
self.logger.info('SerialCommunicator stopped')

0 commit comments

Comments
 (0)