Skip to content

Commit

Permalink
Heiman Siren, see dresden-elektronik#404
Browse files Browse the repository at this point in the history
  • Loading branch information
ebaauw committed Mar 11, 2018
1 parent 306fe9a commit 9c38d59
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 71 deletions.
11 changes: 0 additions & 11 deletions database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2081,17 +2081,6 @@ static int sqliteLoadAllSensorsCallback(void *user, int ncols, char **colval , c
item = sensor.addItem(DataTypeBool, RStateWater);
item->setValue(false);
}
else if (sensor.type().endsWith(QLatin1String("Warning")))
{
if (sensor.fingerPrint().hasInCluster(IAS_WD_CLUSTER_ID))
{
clusterId = IAS_WD_CLUSTER_ID;
}
item = sensor.addItem(DataTypeString, RStateAlert);
item->setValue(QString("none"));
item = sensor.addItem(DataTypeString, RStateEffect);
item->setValue(QString("none"));
}
else if (sensor.type().endsWith(QLatin1String("Consumption")))
{
if (sensor.fingerPrint().hasInCluster(METERING_CLUSTER_ID))
Expand Down
52 changes: 9 additions & 43 deletions de_web_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,12 @@ void DeRestPluginPrivate::addLightNode(const deCONZ::Node *node)
}
break;

case DEV_ID_IAS_WARNING_DEVICE:
{
lightNode.setHaEndpoint(*i);
}
break;

default:
{
}
Expand Down Expand Up @@ -1519,6 +1525,7 @@ LightNode *DeRestPluginPrivate::updateLightNode(const deCONZ::NodeEvent &event)
case DEV_ID_ZLL_ONOFF_PLUGIN_UNIT:
case DEV_ID_Z30_ONOFF_PLUGIN_UNIT:
case DEV_ID_ZLL_ONOFF_SENSOR:
case DEV_ID_IAS_WARNING_DEVICE:
break;

default:
Expand Down Expand Up @@ -2557,7 +2564,6 @@ void DeRestPluginPrivate::addSensorNode(const deCONZ::Node *node, const deCONZ::
SensorFingerprint fpSwitch;
SensorFingerprint fpTemperatureSensor;
SensorFingerprint fpWaterSensor;
SensorFingerprint fpWarningSensor;

{ // scan client clusters of endpoint
QList<deCONZ::ZclCluster>::const_iterator ci = i->outClusters().constBegin();
Expand Down Expand Up @@ -2662,7 +2668,6 @@ void DeRestPluginPrivate::addSensorNode(const deCONZ::Node *node, const deCONZ::
fpSwitch.inClusters.push_back(ci->id());
fpTemperatureSensor.inClusters.push_back(ci->id());
fpWaterSensor.inClusters.push_back(ci->id());
fpWarningSensor.inClusters.push_back(ci->id());
// }
}
break;
Expand Down Expand Up @@ -2775,13 +2780,6 @@ void DeRestPluginPrivate::addSensorNode(const deCONZ::Node *node, const deCONZ::
}
break;

case IAS_WD_CLUSTER_ID:
if (modelId == QLatin1String("WarningDevice")) // Heiman siren
{
fpWarningSensor.inClusters.push_back(ci->id());
}
break;

case OCCUPANCY_SENSING_CLUSTER_ID:
{
// @manup: Does this sensor indeed have an OCCUPANCY_SENSING_CLUSTER_ID custer?
Expand Down Expand Up @@ -2949,7 +2947,6 @@ void DeRestPluginPrivate::addSensorNode(const deCONZ::Node *node, const deCONZ::
// ZHAPresence
if (fpPresenceSensor.hasInCluster(OCCUPANCY_SENSING_CLUSTER_ID) ||
fpPresenceSensor.hasInCluster(IAS_ZONE_CLUSTER_ID) ||
fpPresenceSensor.hasInCluster(IAS_WD_CLUSTER_ID) ||
fpPresenceSensor.hasOutCluster(ONOFF_CLUSTER_ID))
{
fpPresenceSensor.endpoint = i->endpoint();
Expand Down Expand Up @@ -3112,24 +3109,6 @@ void DeRestPluginPrivate::addSensorNode(const deCONZ::Node *node, const deCONZ::
}
}

// ZHAWarning
if (fpWarningSensor.hasInCluster(IAS_WD_CLUSTER_ID))
{
fpWarningSensor.endpoint = i->endpoint();
fpWarningSensor.deviceId = i->deviceId();
fpWarningSensor.profileId = i->profileId();

sensor = getSensorNodeForFingerPrint(node->address().ext(), fpWarningSensor, "ZHAWarning");
if (!sensor || sensor->deletedState() != Sensor::StateNormal)
{
addSensorNode(node, fpWarningSensor, "ZHAWarning", modelId, manufacturer);
}
else
{
checkSensorNodeReachable(sensor);
}
}

// ZHAConsumption
if (fpConsumptionSensor.hasInCluster(METERING_CLUSTER_ID) ||
fpConsumptionSensor.hasInCluster(ANALOG_INPUT_CLUSTER_ID))
Expand Down Expand Up @@ -3285,10 +3264,6 @@ void DeRestPluginPrivate::addSensorNode(const deCONZ::Node *node, const SensorFi
{
clusterId = OCCUPANCY_SENSING_CLUSTER_ID;
}
else if (sensorNode.fingerPrint().hasInCluster(IAS_WD_CLUSTER_ID))
{
clusterId = IAS_WD_CLUSTER_ID;
}
else if (sensorNode.fingerPrint().hasInCluster(IAS_ZONE_CLUSTER_ID))
{
clusterId = IAS_ZONE_CLUSTER_ID;
Expand Down Expand Up @@ -3351,17 +3326,6 @@ void DeRestPluginPrivate::addSensorNode(const deCONZ::Node *node, const SensorFi
item = sensorNode.addItem(DataTypeBool, RStateWater);
item->setValue(false);
}
else if (sensorNode.type().endsWith(QLatin1String("Warning")))
{
if (sensorNode.fingerPrint().hasInCluster(IAS_WD_CLUSTER_ID))
{
clusterId = IAS_WD_CLUSTER_ID;
}
item = sensorNode.addItem(DataTypeString, RStateAlert);
item->setValue(QString("none"));
item = sensorNode.addItem(DataTypeString, RStateEffect);
item->setValue(QString("none"));
}
else if (sensorNode.type().endsWith(QLatin1String("Consumption")))
{
if (sensorNode.fingerPrint().hasInCluster(METERING_CLUSTER_ID))
Expand Down Expand Up @@ -12593,6 +12557,8 @@ void DeRestPluginPrivate::pushSensorInfoToCore(Sensor *sensor)
{ } // use name from light
else if (sensor->modelId() == QLatin1String("SML001") && sensor->type() != QLatin1String("ZHAPresence"))
{ } // use name from ZHAPresence sensor only
else if (sensor->modelId() == QLatin1String("WarningDevice") && sensor->type() == QLatin1String("ZHAAlarm"))
{ } // use name from light
else if (!sensor->name().isEmpty())
{
q->nodeUpdated(sensor->address().ext(), QLatin1String("name"), sensor->name());
Expand Down
7 changes: 6 additions & 1 deletion de_web_plugin_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@

//
#define DEV_ID_IAS_ZONE 0x0402 // IAS Zone
#define DEV_ID_IAS_WARNING_DEVICE 0x0403 // IAS Warning Device
// Smart Energy devices
#define DEV_ID_SE_METERING_DEVICE 0x0501 // Smart Energy metering device

Expand Down Expand Up @@ -466,7 +467,8 @@ enum TaskType
TaskAddToGroup = 30,
TaskRemoveFromGroup = 31,
TaskViewGroup = 32,
TaskTriggerEffect = 33
TaskTriggerEffect = 33,
TaskWarning = 34
};

struct TaskItem
Expand Down Expand Up @@ -501,6 +503,8 @@ struct TaskItem
qreal hueReal;
uint16_t identifyTime;
uint8_t effectIdentifier;
uint8_t options;
uint16_t duration;
uint8_t hue;
uint8_t sat;
uint8_t level;
Expand Down Expand Up @@ -1029,6 +1033,7 @@ public Q_SLOTS:
bool addTaskSetColorLoop(TaskItem &task, bool colorLoopActive, uint8_t speed);
bool addTaskIdentify(TaskItem &task, uint16_t identifyTime);
bool addTaskTriggerEffect(TaskItem &task, uint8_t effectIdentifier);
bool addTaskWarning(TaskItem &task, uint8_t options, uint16_t duration);
bool addTaskAddToGroup(TaskItem &task, uint16_t groupId);
bool addTaskViewGroup(TaskItem &task, uint16_t groupId);
bool addTaskRemoveFromGroup(TaskItem &task, uint16_t groupId);
Expand Down
7 changes: 5 additions & 2 deletions light_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,14 @@ void LightNode::setManufacturerCode(uint16_t code)
case VENDOR_IKEA: m_manufacturer = QLatin1String("IKEA of Sweden"); break;
case VENDOR_INNR: m_manufacturer = QLatin1String("innr"); break;
case VENDOR_INNR2: m_manufacturer = QLatin1String("innr"); break;
case VENDOR_INSTA: m_manufacturer = QLatin1String("Insta"); break;
case VENDOR_INSTA: m_manufacturer = QLatin1String("Insta"); break;
case VENDOR_PHILIPS: m_manufacturer = QLatin1String("Philips"); break;
case VENDOR_OSRAM_STACK: // fall through
case VENDOR_OSRAM: m_manufacturer = QLatin1String("OSRAM"); break;
case VENDOR_UBISYS: m_manufacturer = QLatin1String("ubisys"); break;
case VENDOR_BUSCH_JAEGER: m_manufacturer = QLatin1String("Busch-Jaeger"); break;
case VENDOR_EMBER: m_manufacturer = QLatin1String("Heiman"); break;
case VENDOR_EMBER: // fall through
case VENDOR_120B: m_manufacturer = QLatin1String("Heiman"); break;
default:
m_manufacturer = QLatin1String("Unknown");
break;
Expand Down Expand Up @@ -563,6 +564,8 @@ void LightNode::setHaEndpoint(const deCONZ::SimpleDescriptor &endpoint)
case DEV_ID_Z30_COLOR_TEMPERATURE_LIGHT: ltype = QLatin1String("Color temperature light"); break;
case DEV_ID_ZLL_COLOR_TEMPERATURE_LIGHT: ltype = QLatin1String("Color temperature light"); break;
case DEV_ID_XIAOMI_SMART_PLUG: ltype = QLatin1String("Smart plug"); break;
case DEV_ID_IAS_WARNING_DEVICE: removeItem(RStateOn);
ltype = QLatin1String("Warning device"); break;
default:
break;
}
Expand Down
66 changes: 52 additions & 14 deletions rest_lights.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -987,48 +987,85 @@ int DeRestPluginPrivate::setLightState(const ApiRequest &req, ApiResponse &rsp)
TaskItem task;
copyTaskReq(taskRef, task);
QString alert = map["alert"].toString();
bool isWarningDevice = taskRef.lightNode->type() == QLatin1String("Warning device");

if (alert == "none")
{
task.taskType = TaskIdentify;
task.identifyTime = 0;
if (isWarningDevice)
{
task.taskType = TaskWarning;
task.options = 0x00; // Warning mode 0 (no warning), No strobe
task.duration = 0;
}
else
{
task.taskType = TaskIdentify;
task.identifyTime = 0;
}
}
else if (alert == "select")
{
task.taskType = TaskIdentify;
task.identifyTime = 2; // Hue lights don't react to 1.
if (isWarningDevice)
{
task.taskType = TaskWarning;
task.options = 0x14; // Warning mode 1 (burglar), Strobe
task.duration = 1;
}
else
{
task.taskType = TaskIdentify;
task.identifyTime = 2; // Hue lights don't react to 1.
}
}
else if (alert == "lselect")
{
task.taskType = TaskIdentify;
task.identifyTime = 15; // Default for Philips Hue bridge
if (isWarningDevice)
{
task.taskType = TaskWarning;
task.options = 0x14; // Warning mode 1 (burglar), Strobe
task.duration = 300;
}
else
{
task.taskType = TaskIdentify;
task.identifyTime = 15; // Default for Philips Hue bridge
}
}
else if (alert == "blink")
{
task.taskType = TaskTriggerEffect;
task.effectIdentifier = 0x00;
if (isWarningDevice)
{
task.taskType = TaskWarning;
task.options = 0x04; // Warning mode 0 (no warning), Strobe
task.duration = 300;
}
else
{
task.taskType = TaskTriggerEffect;
task.effectIdentifier = 0x00;
}
}
else if (alert == "breathe")
else if (alert == "breathe" && !isWarningDevice)
{
task.taskType = TaskTriggerEffect;
task.effectIdentifier = 0x01;
}
else if (alert == "okay")
else if (alert == "okay" && !isWarningDevice)
{
task.taskType = TaskTriggerEffect;
task.effectIdentifier = 0x02;
}
else if (alert == "channelchange")
else if (alert == "channelchange" && !isWarningDevice)
{
task.taskType = TaskTriggerEffect;
task.effectIdentifier = 0x0b;
}
else if (alert == "finish")
else if (alert == "finish" && !isWarningDevice)
{
task.taskType = TaskTriggerEffect;
task.effectIdentifier = 0xfe;
}
else if (alert == "stop")
else if (alert == "stop" && !isWarningDevice)
{
task.taskType = TaskTriggerEffect;
task.effectIdentifier = 0xff;
Expand All @@ -1043,7 +1080,8 @@ int DeRestPluginPrivate::setLightState(const ApiRequest &req, ApiResponse &rsp)
taskToLocalData(task);

if ((task.taskType == TaskIdentify && addTaskIdentify(task, task.identifyTime)) ||
(task.taskType == TaskTriggerEffect && addTaskTriggerEffect(task, task.effectIdentifier)))
(task.taskType == TaskTriggerEffect && addTaskTriggerEffect(task, task.effectIdentifier)) ||
(task.taskType == TaskWarning && addTaskWarning(task, task.options, task.duration)))
{
QVariantMap rspItem;
QVariantMap rspItemState;
Expand Down
46 changes: 46 additions & 0 deletions zcl_tasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,52 @@ bool DeRestPluginPrivate::addTaskTriggerEffect(TaskItem &task, uint8_t effectIde
return addTask(task);
}

/*! Add a warning task to the queue.
\param task - the task item
\param options - the options
\param duration - the duration
\return true - on success
false - on error
*/
bool DeRestPluginPrivate::addTaskWarning(TaskItem &task, uint8_t options, uint16_t duration)
{
task.taskType = TaskWarning;
task.options = options;
task.duration = duration;
uint8_t strobe_duty_cycle = 10;
uint8_t strobe_level = 0;

task.req.setClusterId(IAS_WD_CLUSTER_ID);
task.req.setProfileId(HA_PROFILE_ID);

task.zclFrame.payload().clear();
task.zclFrame.setSequenceNumber(zclSeq++);
task.zclFrame.setCommandId(0x00); // Start Warning
task.zclFrame.setFrameControl(deCONZ::ZclFCClusterCommand |
deCONZ::ZclFCDirectionClientToServer |
deCONZ::ZclFCDisableDefaultResponse);

{ // payload
QDataStream stream(&task.zclFrame.payload(), QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);

stream << task.options;
stream << task.duration;
stream << strobe_duty_cycle;
stream << strobe_level;
}

{ // ZCL frame
task.req.asdu().clear(); // cleanup old request data if there is any
QDataStream stream(&task.req.asdu(), QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
task.zclFrame.writeToStream(stream);
}

return addTask(task);
}

/*! Add a add to group task to the queue.
\param task - the task item
Expand Down

0 comments on commit 9c38d59

Please sign in to comment.