Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing device class #24

Open
TheMeaningfulEngineer opened this issue Feb 18, 2016 · 5 comments
Open

Missing device class #24

TheMeaningfulEngineer opened this issue Feb 18, 2016 · 5 comments

Comments

@TheMeaningfulEngineer
Copy link

So far I have a successful communication example of controlling an EnOcean actuator.
I seem to be missing a Devce class which would represent a device.

Use case example:

  1. Device object is initialised with profile and chipid received from the TEACHIN packet
  2. After a successful teach in procedure the physical device start sending DATA packets.
  3. Because the DATA packets are sent from a familiar chipid we map it to the Device object and have the profile for data packets.

I will start an implementation and if it matures will make a pull request

@kipe
Copy link
Owner

kipe commented Feb 18, 2016

I have (at least so far) left this out on purpose, as in my use-case I have implemented a similar solution in elsewhere in my code. Of course, it wouldn't hurt to have a "meta" -class from which to inherit the use-case specific solutions...

@kipe
Copy link
Owner

kipe commented Feb 25, 2016

Yeah, seems like it's worth implementing with issue #26.
I'm currently returning a dictionary from the storage, which is not nice :(

As I'm currently implementing the storage, the prototype for Device class would be something like:

class Device(object):
    id = [0xDE, 0xAD, 0xBE, 0xEF]
    eep_rorg = 0x00
    eep_func = 0x00
    eep_type = 0x00
    transmitter_offset =  None

    @staticmethod
    def from_dict(self, dictionary):
        return new DeviceObject

    def to_dict(self):
        return {
            'eep_rorg': self.eep_rorg,
            'eep_func': self.eep_func,
            'eep_type': self.eep_type,
            'transmitter_offset': self.transmitter_offset,
        }

@kipe
Copy link
Owner

kipe commented Feb 25, 2016

Oh, and also to note, I'm currently implementing the storage to enocean/storage.
As the Device isn't part of the protocol, in my opinion it should not go to enocean/protocol, so the next best thing would be to use enocean/storage/device.py for that, as the devices should (again IMO) always be linked to storage.

@TheMeaningfulEngineer
Copy link
Author

I would like to share the way I've implemented the device, just in case it provides helpful.
My reasoning is that the device, once successfully created, is responsible for handling it's own packages and provide an abstraction of an expected and actual state based on the sent and received packets.

I've you agree with this reasoning, I will make a pull request on which we could comment more.

from enocean import utils
from enocean.protocol.packet import RadioPacket
import logging


logger = logging.getLogger('enocean.genericBS4Device')

class GenericBS4Device(object):
    '''An in code representation of the physical enocean device. It is created
    when a teach in packet form a physical device is received on the controller.
    '''

    def __init__(self, teachInPacket, transmitter_id, communicator):

        teachInPacket.parse_eep(teachInPacket.rorg_func, teachInPacket.rorg_type, 1)

        self.chipId = teachInPacket.sender
        self.rorg = teachInPacket.rorg
        self.function = teachInPacket.rorg_func
        self.type = teachInPacket.rorg_type
        self.profile = str(hex(self.rorg)) + "-" + str(hex(self.function)) + "-" + str(hex(self.type))

        self.confirmedTeachIn = False
        '''In case we respond to a devices Teachin packet with our Teachin packet
        after which the device starts normally communicating with us, we confirm
        that the Teachin was successful and turn this to True '''

        self.communicator = communicator
        '''A reference to the communicator class. Motivation behind this is
        be able to extend the device with a send method which will also
        update the device status.'''
        self.transmitter_id = transmitter_id
        '''The packets that are sent to the physical enocean device are sent from
        the gateway. The create the packet the transmitter_id must me kown for it 
        is the source address for every packet sent from the controller.
        Not to be confused with chipId.
        '''

        self.fs_metadata = None        
        self.reportedState = None
        self.expectedState = None

        self.packetToSend = None

        logger.debug("Initializing new device. Id: %s. " % self.chipId_hex)

    def __generateTeachInResponsePacket(self):
        '''Generates the packet that is to be sent to the physical counterpart 
        of this device'''
        pass

    def send(self):
        '''By sending the packet to the physical device, we're hoping
        to change the state of that device. Because of that, the
        expectedState is updated on each packet sending.

        self.packetToSend.parse_eep(self.function, self.type, 2)
        self.expectedState = self.packetToSend.parsed
        self.communicator.send(self.packetToSend)
        logger.info("Sending packet to %s. " % self.chipId_hex)


    def recieve(self,packet):
        packet.parse_eep(self.function, self.type, 1)
        self.reportedState = packet.parsed

    def respondToTeachIn(self):
        '''Sent the teachIn response to the physical counterpart.
        So far I haven't found a generic way for this so it should be
        implemented by the subclass''
        raise NotImplementedError()
        #self.communicator.send(self.responseTeachInPacket)

    @property
    def chipId_hex(self):
        return utils.to_hex_string(self.chipId_hex)

    def __str__(self):
        deviceStr = "\nDevice (%s) (%s) \n" % (self.chipId_hex, self.profile)
        deviceStr += "Teach in confirmed: %s " % self.confirmedTeachIn
        deviceStr += "\nReported state: \n " + self.printReportedState()
        deviceStr += "\nExpected state: \n " + self.printExpectedState()
        return deviceStr

    def printExpectedState(self):
        expectedStateAsString = ""
        try:
            for attribute in self.expectedState.values():
                expectedStateAsString += "\t" + attribute['description'] + " : " + str(attribute['value']) + "\n"
        except AttributeError:
            expectedStateAsString = "\tNone available"
        return expectedStateAsString

    def printReportedState(self):
        reportedStateAsString = ""
        try:
            for attribute in self.reportedState.values():
                reportedStateAsString += "\t" + attribute['description'] + " : " + str(attribute['value']) + "\n"
        except AttributeError:
            reportedStateAsString = "\tNone available"
        return reportedStateAsString

@kipe
Copy link
Owner

kipe commented Mar 1, 2016

Thanks, I'm actually in the progress of implementing something fairly similar as part of storage (issue #26 ).

I'm more likely to implement a very basic storage.Device at first, then look into if we need to extend it to different types. The main idea is to save the information about EEP at least in the first revision.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants