# -*- coding: utf-8 -*- from datetime import datetime from sqlalchemy import Column, Integer, Float, DateTime, String, ForeignKey from sqlalchemy.orm import relationship, backref from sqlalchemy.ext.declarative import declarative_base from ebus import model ModelBase = declarative_base() class Sensor(ModelBase): __tablename__ = 'sensor' id = Column(Integer, primary_key=True) name = Column(String) description = Column(String, default="") def __init__(self, name, description=""): self.name = name self.description = description def __repr__(self): return "" % (self.id, self.name, self.description) # http://www.sqlalchemy.org/docs/05/reference/ext/declarative.html#inheritance-configuration class Value(ModelBase): __tablename__ = 'value' id = Column(Integer, primary_key=True) timestamp = Column(DateTime,index=True) sensor_id = Column(Integer,ForeignKey("sensor.id"),index=True) sensor = relationship(Sensor, backref=backref('values', order_by=timestamp)) discriminator = Column('type', String(50)) __mapper_args__ = {'polymorphic_on': discriminator} def __init__(self, sensor, timestamp=None): if not timestamp: timestamp = datetime.now() self.timestamp = timestamp self.sensor = sensor def __repr__(self): return "" % ( self.id, self.sensor, self.value(), self.timestamp) def value(self): raise NotImplementedException() class ValueFloat(Value): __mapper_args__ = {'polymorphic_identity': 'float'} value_float = Column(Float(precision=4)) def __init__(self, sensor, value, timestamp=None): Value.__init__(self, sensor, timestamp) self.value_float = value def value(self): return self.value_float class ValueInt(Value): __mapper_args__ = {'polymorphic_identity': 'int'} value_int = Column(Integer) def __init__(self, sensor, value, timestamp=None): Value.__init__(self, sensor, timestamp) self.value_int = value def value(self): return self.value_int class ValueString(Value): __mapper_args__ = {'polymorphic_identity': 'string'} value_string = Column(String) def __init__(self, sensor, value, timestamp=None): Value.__init__(self, sensor, timestamp) self.value_string = value def value(self): return self.value_string class EbusSQL(object): def __init__(self,session): self.session = session def get_values(self,packet): packet_description = packet.get_packet_description() packet_source_name = packet.get_source_name() packet_name = packet.name() for field in packet_description.fields.iterchildren(): try: name = field.get("name") offset = int(field.get("offset")) if not name: continue sensor_name = "%s.%s.%s" % (packet_source_name, packet_name, name ) sensor = self.session.query(Sensor) \ .filter(Sensor.name==sensor_name).first() if sensor is None: sensor = Sensor(sensor_name) self.session.add(sensor) if field.tag == "bit": yield ValueInt(sensor, \ model.Bit(name, offset).value(packet.data) and 1 or 0) elif field.tag == "byte": yield ValueInt(sensor, \ model.Byte(name, offset).value(packet.data)) elif field.tag == "word": yield ValueInt(sensor, \ model.Word(name, offset).value(packet.data)) elif field.tag == "data1b": yield ValueFloat(sensor, \ model.Data1b(name, offset).value(packet.data)) elif field.tag == "data1c": yield ValueFloat(sensor, \ model.Data1c(name, offset).value(packet.data)) elif field.tag == "data2b": yield ValueFloat(sensor, \ model.Data2b(name, offset).value(packet.data)) elif field.tag == "data2c": yield ValueFloat(sensor, model.Data2c(name, offset).value(packet.data)) elif field.tag == "bcd": yield ValueInt(sensor, model.Bcd(name, offset).value(packet.data)) elif field.tag == "byteEnum": options = dict(map(lambda opt: ( int(opt.get("value")[2:],16), opt.get("name")), field.xpath("./option"))) yield ValueString(sensor, model.ByteEnum(name, offset, options).value(packet.data)) else: print "Unsupported field-type %s" % (name) except Exception,e: print "skip",e