"""Generic Z Wave device driver."""

import logging

from google.appengine.ext import ndb

from appengine import device, pushrpc


class CommandClassValue(ndb.Model):
  """A particular (command class, value)."""

  command_class = ndb.StringProperty()
  index = ndb.IntegerProperty()
  value = ndb.GenericProperty()
  read_only = ndb.BooleanProperty()
  units = ndb.StringProperty()
  genre = ndb.StringProperty()
  label = ndb.StringProperty()
  type = ndb.StringProperty()


@device.register('zwave')
class ZWaveDevice(device.Device):
  """Generic Z Wave device driver."""
  zwave_node_id = ndb.IntegerProperty(required=False)
  zwave_home_id = ndb.IntegerProperty(required=False)
  zwave_command_class_values = ndb.StructuredProperty(
      CommandClassValue, repeated=True)

  def __init__(self, **kwargs):
    super(ZWaveDevice, self).__init__(**kwargs)

  def _command_class_value(self, command_class, index):
    """Find the given (command_class, index) or create a new one."""
    for ccv in self.zwave_command_class_values:
      if ccv.command_class == command_class and ccv.index == index:
        return ccv
    ccv = CommandClassValue(command_class=command_class, index=index)
    self.zwave_command_class_values.append(ccv)
    return ccv

  def handle_event(self, event):
    """Handle an event form the zwave device."""
    super(ZWaveDevice, self).handle_event(event)

    notification_type = event['notificationType']
    self.zwave_home_id = event['homeId']
    self.zwave_node_id = event['nodeId']

    if notification_type in {'ValueAdded', 'ValueChanged'}:
      value = event['valueId']
      command_class = value.pop('commandClass')
      index = value.pop('index')
      value['read_only'] = value['readOnly']
      del value['homeId']
      del value['nodeId']
      del value['readOnly']
      del value['instance']
      del value['id']

      ccv = self._command_class_value(command_class, index)
      ccv.populate(**value)

      logging.info('%s.%s[%d] <- %s', self.zwave_node_id,
                   command_class, index, value)

      if command_class == 'COMMAND_CLASS_SENSOR_BINARY':
        self.lights(value['value'])

    elif notification_type == 'NodeNaming':
      logging.info(event)

  @device.command
  def lights(self, state):
    """Turn the lights on/off in the room this sensor is in."""
    room_key = self.room
    if not room_key:
      return

    switches = device.Switch.query().filter(
        device.Device.room == room_key).iter()
    for switch in switches:
      if state:
        switch.turn_on()
      else:
        switch.turn_off()

  @classmethod
  @device.static_command
  def heal(cls, user_id):
    event = {'type': 'zwave', 'command': 'heal'}
    pushrpc.send_event(user_id, event)

@@ -438,16 +438,51 @@
 perty()%0A
+  value_id = ndb.IntegerProperty()%0A
   type =
@@ -1747,25 +1747,29 @@
 ly'%5D = value
-%5B
+.pop(
 'readOnly'%5D%0A
@@ -1758,33 +1758,75 @@
 e.pop('readOnly'
-%5D
+)%0A      value%5B'value_id'%5D = value.pop('id')
 %0A      del value
@@ -1883,66 +1883,16 @@
 ue%5B'
-readOnly'%5D%0A      del value%5B'instance'%5D%0A      del value%5B'id
+instance
 '%5D%0A%0A

Add value ids to zwave command classes.