json_spirit::Object ZWaveController::GetValue(uint64 value_id){ EnterCriticalSection(&g_criticalSection); json_spirit::Object rtn; bool found = false; for (list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it) { NodeInfo* nodeInfo = *it; for (list<ValueID>::iterator it2 = nodeInfo->m_values.begin(); it2 != nodeInfo->m_values.end(); ++it2) { ValueID v = *it2; uint64 vid = v.GetId(); if (vid == value_id && ZWaveController::ExposeValue(v)){ rtn.push_back(json_spirit::Pair("value", ZWaveController::GetValueInfo(v))); found = true; break; } } if (found){ break; } } LeaveCriticalSection(&g_criticalSection); return rtn; }
bool ZWaveController::RefreshValue(uint64 value_id, string &error_msg){ EnterCriticalSection(&g_criticalSection); bool success = false; bool found = false; error_msg = ""; for (list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it) { NodeInfo* nodeInfo = *it; for (list<ValueID>::iterator it2 = nodeInfo->m_values.begin(); it2 != nodeInfo->m_values.end(); ++it2) { ValueID v = *it2; uint64 vid = v.GetId(); int node_id = v.GetNodeId(); if (vid == value_id){ found = true; success = Manager::Get()->RefreshValue(v); if (!success){ error_msg = "Call to ZWave library RefreshValue failed (returned false)"; } break; } } } LeaveCriticalSection(&g_criticalSection); if (!found){ error_msg = "Value id " + to_string(value_id) + " could not be found"; } return success; }
json_spirit::Object ZWaveController::GetValueChangesSince(uint64 since_milliseconds, uint64 only_node_id){ if (since_milliseconds < ZWaveController::expire_seconds){ return ZWaveController::GetAllValues(only_node_id); } json_spirit::Object rtn; uint64 current_milliseconds = Utils::GetTimeMilliseconds(); string s_current_milliseconds = boost::lexical_cast<string>(current_milliseconds); rtn.push_back(json_spirit::Pair("time", s_current_milliseconds)); std::vector<json_spirit::Value> values; EnterCriticalSection(&g_criticalSection); for (std::vector<ValueChange>::iterator i = ValueChange::value_changes.begin(); i != ValueChange::value_changes.end(); ++i){ ValueChange vc = *i; if (i->time_added >= since_milliseconds && i->time_added <= current_milliseconds - 1){ for (list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it) { NodeInfo* nodeInfo = *it; if (only_node_id != 0 && only_node_id != (uint64)nodeInfo->m_nodeId){ continue; } for (list<ValueID>::iterator it2 = nodeInfo->m_values.begin(); it2 != nodeInfo->m_values.end(); ++it2) { ValueID v = *it2; uint64 vid = v.GetId(); if (vid == vc.value_id && ZWaveController::ExposeValue(v)){ values.push_back(ZWaveController::GetValueInfo(v)); } } } } } LeaveCriticalSection(&g_criticalSection); rtn.push_back(json_spirit::Pair("values", values)); return rtn; }
bool ZWaveController::ExposeValue(ValueID v){ return true; switch (v.GetGenre()){ case ValueID::ValueGenre::ValueGenre_Basic: case ValueID::ValueGenre::ValueGenre_User: case ValueID::ValueGenre::ValueGenre_Config: return true; case ValueID::ValueGenre::ValueGenre_System: case ValueID::ValueGenre::ValueGenre_Count: default: return false; } }
/* * MyNode::removeValue * Per notification, remove value from node. */ void MyNode::removeValue (ValueID id) { vector<MyValue*>::iterator it; bool found = false; for (it = values.begin(); it != values.end(); it++) { if ((*it)->id == id) { delete *it; values.erase(it); found = true; break; } } if (!found) fprintf(stderr, "removeValue not found Home 0x%08x Node %d Genre %s Class %s Instance %d Index %d Type %s\n", id.GetHomeId(), id.GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); setTime(time(NULL)); setChanged(true); }
//----------------------------------------------------------------------------- // <OnNotification> // Callback that is triggered when a value, group or node changes //----------------------------------------------------------------------------- void OnNotification (Notification const* _notification, void* _context) { ValueID id = _notification->GetValueID(); switch (_notification->GetType()) { case Notification::Type_ValueAdded: Log::Write(LogLevel_Info, "Notification: Value Added Home 0x%08x Node %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->addValue(id); nodes[_notification->GetNodeId()]->setTime(time(NULL)); nodes[_notification->GetNodeId()]->setChanged(true); pthread_mutex_unlock(&nlock); break; case Notification::Type_ValueRemoved: Log::Write(LogLevel_Info, "Notification: Value Removed Home 0x%08x Node %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->removeValue(id); nodes[_notification->GetNodeId()]->setTime(time(NULL)); nodes[_notification->GetNodeId()]->setChanged(true); pthread_mutex_unlock(&nlock); break; case Notification::Type_ValueChanged: Log::Write(LogLevel_Info, "Notification: Value Changed Home 0x%08x Node %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->saveValue(id); pthread_mutex_unlock(&nlock); break; case Notification::Type_ValueRefreshed: Log::Write(LogLevel_Info, "Notification: Value Refreshed Home 0x%08x Node %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->setTime(time(NULL)); nodes[_notification->GetNodeId()]->setChanged(true); pthread_mutex_unlock(&nlock); break; case Notification::Type_Group: { Log::Write(LogLevel_Info, "Notification: Group Home 0x%08x Node %d Group %d", _notification->GetHomeId(), _notification->GetNodeId(), _notification->GetGroupIdx()); uint8 *v = NULL; int8 n = Manager::Get()->GetAssociations(homeId, _notification->GetNodeId(), _notification->GetGroupIdx(), &v); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->addGroup(_notification->GetNodeId(), _notification->GetGroupIdx(), n, v); pthread_mutex_unlock(&nlock); if (v != NULL) delete [] v; } break; case Notification::Type_NodeNew: Log::Write(LogLevel_Info, "Notification: Node New Home %08x Node %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); pthread_mutex_lock(&glock); needsave = true; pthread_mutex_unlock(&glock); break; case Notification::Type_NodeAdded: Log::Write(LogLevel_Info, "Notification: Node Added Home %08x Node %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); pthread_mutex_lock(&nlock); new MyNode(_notification->GetNodeId()); pthread_mutex_unlock(&nlock); pthread_mutex_lock(&glock); needsave = true; pthread_mutex_unlock(&glock); break; case Notification::Type_NodeRemoved: Log::Write(LogLevel_Info, "Notification: Node Removed Home %08x Node %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); pthread_mutex_lock(&nlock); MyNode::remove(_notification->GetNodeId()); pthread_mutex_unlock(&nlock); pthread_mutex_lock(&glock); needsave = true; pthread_mutex_unlock(&glock); break; case Notification::Type_NodeProtocolInfo: Log::Write(LogLevel_Info, "Notification: Node Protocol Info Home %08x Node %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->saveValue(id); pthread_mutex_unlock(&nlock); pthread_mutex_lock(&glock); needsave = true; pthread_mutex_unlock(&glock); break; case Notification::Type_NodeNaming: Log::Write(LogLevel_Info, "Notification: Node Naming Home %08x Node %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->saveValue(id); pthread_mutex_unlock(&nlock); break; case Notification::Type_NodeEvent: Log::Write(LogLevel_Info, "Notification: Node Event Home %08x Node %d Status %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), _notification->GetEvent(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->saveValue(id); pthread_mutex_unlock(&nlock); break; case Notification::Type_PollingDisabled: Log::Write(LogLevel_Info, "Notification: Polling Disabled Home %08x Node %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); //pthread_mutex_lock(&nlock); //nodes[_notification->GetNodeId()]->setPolled(false); //pthread_mutex_unlock(&nlock); break; case Notification::Type_PollingEnabled: Log::Write(LogLevel_Info, "Notification: Polling Enabled Home %08x Node %d Genre %s Class %s Instance %d Index %d Type %s", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType())); //pthread_mutex_lock(&nlock); //nodes[_notification->GetNodeId()]->setPolled(true); //pthread_mutex_unlock(&nlock); break; case Notification::Type_SceneEvent: Log::Write(LogLevel_Info, "Notification: Scene Event Home %08x Node %d Genre %s Class %s Instance %d Index %d Type %s Scene Id %d", _notification->GetHomeId(), _notification->GetNodeId(), valueGenreStr(id.GetGenre()), cclassStr(id.GetCommandClassId()), id.GetInstance(), id.GetIndex(), valueTypeStr(id.GetType()), _notification->GetSceneId()); break; case Notification::Type_CreateButton: Log::Write(LogLevel_Info, "Notification: Create button Home %08x Node %d Button %d", _notification->GetHomeId(), _notification->GetNodeId(), _notification->GetButtonId()); break; case Notification::Type_DeleteButton: Log::Write(LogLevel_Info, "Notification: Delete button Home %08x Node %d Button %d", _notification->GetHomeId(), _notification->GetNodeId(), _notification->GetButtonId()); break; case Notification::Type_ButtonOn: Log::Write(LogLevel_Info, "Notification: Button On Home %08x Node %d Button %d", _notification->GetHomeId(), _notification->GetNodeId(), _notification->GetButtonId()); break; case Notification::Type_ButtonOff: Log::Write(LogLevel_Info, "Notification: Button Off Home %08x Node %d Button %d", _notification->GetHomeId(), _notification->GetNodeId(), _notification->GetButtonId()); break; case Notification::Type_DriverReady: Log::Write(LogLevel_Info, "Notification: Driver Ready, homeId %08x, nodeId %d", _notification->GetHomeId(), _notification->GetNodeId()); pthread_mutex_lock(&glock); homeId = _notification->GetHomeId(); nodeId = _notification->GetNodeId(); if (Manager::Get()->IsStaticUpdateController(homeId)) { cmode = "SUC"; SUCnodeId = Manager::Get()->GetSUCNodeId(homeId); } else if (Manager::Get()->IsPrimaryController(homeId)) cmode = "Primary"; else cmode = "Slave"; pthread_mutex_unlock(&glock); break; case Notification::Type_DriverFailed: Log::Write(LogLevel_Info, "Notification: Driver Failed, homeId %08x", _notification->GetHomeId()); pthread_mutex_lock(&glock); done = false; needsave = false; homeId = 0; cmode = ""; pthread_mutex_unlock(&glock); pthread_mutex_lock(&nlock); for (int i = 1; i < MAX_NODES; i++) MyNode::remove(i); pthread_mutex_unlock(&nlock); break; case Notification::Type_DriverReset: Log::Write(LogLevel_Info, "Notification: Driver Reset, homeId %08x", _notification->GetHomeId()); pthread_mutex_lock(&glock); done = false; needsave = true; homeId = _notification->GetHomeId(); if (Manager::Get()->IsStaticUpdateController(homeId)) { cmode = "SUC"; SUCnodeId = Manager::Get()->GetSUCNodeId(homeId); } else if (Manager::Get()->IsPrimaryController(homeId)) cmode = "Primary"; else cmode = "Slave"; pthread_mutex_unlock(&glock); pthread_mutex_lock(&nlock); for (int i = 1; i < MAX_NODES; i++) MyNode::remove(i); pthread_mutex_unlock(&nlock); break; case Notification::Type_EssentialNodeQueriesComplete: Log::Write(LogLevel_Info, "Notification: Essential Node %d Queries Complete", _notification->GetNodeId()); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->setTime(time(NULL)); nodes[_notification->GetNodeId()]->setChanged(true); pthread_mutex_unlock(&nlock); break; case Notification::Type_NodeQueriesComplete: Log::Write(LogLevel_Info, "Notification: Node %d Queries Complete", _notification->GetNodeId()); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->sortValues(); nodes[_notification->GetNodeId()]->setTime(time(NULL)); nodes[_notification->GetNodeId()]->setChanged(true); pthread_mutex_unlock(&nlock); pthread_mutex_lock(&glock); needsave = true; pthread_mutex_unlock(&glock); break; case Notification::Type_AwakeNodesQueried: Log::Write(LogLevel_Info, "Notification: Awake Nodes Queried"); break; case Notification::Type_AllNodesQueriedSomeDead: Log::Write(LogLevel_Info, "Notification: Awake Nodes Queried Some Dead"); break; case Notification::Type_AllNodesQueried: Log::Write(LogLevel_Info, "Notification: All Nodes Queried"); break; case Notification::Type_Notification: switch (_notification->GetNotification()) { case Notification::Code_MsgComplete: Log::Write(LogLevel_Info, "Notification: Notification home %08x node %d Message Complete", _notification->GetHomeId(), _notification->GetNodeId()); break; case Notification::Code_Timeout: Log::Write(LogLevel_Info, "Notification: Notification home %08x node %d Timeout", _notification->GetHomeId(), _notification->GetNodeId()); break; case Notification::Code_NoOperation: Log::Write(LogLevel_Info, "Notification: Notification home %08x node %d No Operation Message Complete", _notification->GetHomeId(), _notification->GetNodeId()); pthread_mutex_lock(&glock); noop = true; pthread_mutex_unlock(&glock); break; case Notification::Code_Awake: Log::Write(LogLevel_Info, "Notification: Notification home %08x node %d Awake", _notification->GetHomeId(), _notification->GetNodeId()); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->setTime(time(NULL)); nodes[_notification->GetNodeId()]->setChanged(true); pthread_mutex_unlock(&nlock); break; case Notification::Code_Sleep: Log::Write(LogLevel_Info, "Notification: Notification home %08x node %d Sleep", _notification->GetHomeId(), _notification->GetNodeId()); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->setTime(time(NULL)); nodes[_notification->GetNodeId()]->setChanged(true); pthread_mutex_unlock(&nlock); break; case Notification::Code_Dead: Log::Write(LogLevel_Info, "Notification: Notification home %08x node %d Dead", _notification->GetHomeId(), _notification->GetNodeId()); pthread_mutex_lock(&nlock); nodes[_notification->GetNodeId()]->setTime(time(NULL)); nodes[_notification->GetNodeId()]->setChanged(true); pthread_mutex_unlock(&nlock); break; default: Log::Write(LogLevel_Info, "Notification: Notification home %08x node %d Unknown %d", _notification->GetHomeId(), _notification->GetNodeId(), _notification->GetNotification()); break; } break; case Notification::Type_ControllerCommand: Log::Write(LogLevel_Info, "Notification: ControllerCommand home %08x Event %d Error %d", _notification->GetHomeId(), _notification->GetEvent(), _notification->GetNotification()); pthread_mutex_lock(&nlock); web_controller_update((OpenZWave::Driver::ControllerState)_notification->GetEvent(), (OpenZWave::Driver::ControllerError)_notification->GetNotification(), (void *)_context); pthread_mutex_unlock(&nlock); break; default: Log::Write(LogLevel_Info, "Notification: type %d home %08x node %d genre %d class %d instance %d index %d type %d", _notification->GetType(), _notification->GetHomeId(), _notification->GetNodeId(), id.GetGenre(), id.GetCommandClassId(), id.GetInstance(), id.GetIndex(), id.GetType()); break; } }
void OnNotification(Notification const* _notification, void* _context) { // Must do this inside a critical section to avoid conflicts with the main thread pthread_mutex_lock(&g_criticalSection); switch (_notification->GetType()) { case Notification::Type_ValueAdded: { if (NodeInfo * nodeInfo = GetNodeInfo(_notification)) { // Add the new value to our list nodeInfo->m_values.push_back(_notification->GetValueID()); } break; } case Notification::Type_ValueRemoved: { if (NodeInfo * nodeInfo = GetNodeInfo(_notification)) { // Remove the value from out list for (list<ValueID>::iterator it = nodeInfo->m_values.begin(); it != nodeInfo->m_values.end(); ++it) { if ((*it) == _notification->GetValueID()) { nodeInfo->m_values.erase(it); break; } } } break; } case Notification::Type_ValueChanged: { if (NodeInfo * nodeInfo = GetNodeInfo(_notification)) { // One of the node values has changed // TBD... ValueID id = _notification->GetValueID(); string str; printf("Notification Value Changed: Value Changed Home 0x%08x Node %d Genre %d Class %d Instance %d Index %d Type %d\n", _notification->GetHomeId(), _notification->GetNodeId(), id.GetGenre(), id.GetCommandClassId(), id.GetInstance(), id.GetIndex(), id.GetType()); if (Manager::Get()->GetValueAsString(id, &str)) { int level = 0; printf("Values: %s\n", str.c_str()); level = atoi(str.c_str()); nodeInfo->m_level = level; //printf("Node %d Level %d\n",id, level); //printf("Node %s value %d\n", uuidstr , level); } } break; } case Notification::Type_Group: { if (NodeInfo * nodeInfo = GetNodeInfo(_notification)) { // One of the node's association groups has changed // TBD... nodeInfo = nodeInfo; } break; } case Notification::Type_NodeAdded: { // Add the new node to our list NodeInfo* nodeInfo = new NodeInfo(); nodeInfo->m_homeId = _notification->GetHomeId(); nodeInfo->m_nodeId = _notification->GetNodeId(); nodeInfo->m_polled = false; g_nodes.push_back(nodeInfo); break; } case Notification::Type_NodeRemoved: { // Remove the node from our list uint32 const homeId = _notification->GetHomeId(); uint8 const nodeId = _notification->GetNodeId(); for (list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it) { NodeInfo* nodeInfo = *it; if ((nodeInfo->m_homeId == homeId) && (nodeInfo->m_nodeId == nodeId)) { g_nodes.erase(it); break; } } break; } case Notification::Type_NodeEvent: { if (NodeInfo * nodeInfo = GetNodeInfo(_notification)) { // We have received an event from the node, caused by a // basic_set or hail message. // TBD... nodeInfo = nodeInfo; nodeInfo->m_level = _notification->GetByte(); printf("\n\n\nReceived Node Event with value %s\n\n\n", nodeInfo->m_level); } break; } case Notification::Type_PollingDisabled: { if (NodeInfo * nodeInfo = GetNodeInfo(_notification)) { nodeInfo->m_polled = false; } break; } case Notification::Type_PollingEnabled: { if (NodeInfo * nodeInfo = GetNodeInfo(_notification)) { nodeInfo->m_polled = true; } break; } case Notification::Type_DriverReady: { g_homeId = _notification->GetHomeId(); break; } case Notification::Type_DriverFailed: { g_initFailed = true; pthread_cond_broadcast(&initCond); break; } case Notification::Type_AwakeNodesQueried: case Notification::Type_AllNodesQueried: { pthread_cond_broadcast(&initCond); break; } default: { } } pthread_mutex_unlock(&g_criticalSection); }
bool ZWaveController::SetValue(uint64 value_id, string new_value, string &error_msg){ EnterCriticalSection(&g_criticalSection); bool success = false; bool found = false; error_msg = ""; for (list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it) { NodeInfo* nodeInfo = *it; for (list<ValueID>::iterator it2 = nodeInfo->m_values.begin(); it2 != nodeInfo->m_values.end(); ++it2) { ValueID v = *it2; uint64 vid = v.GetId(); int node_id = v.GetNodeId(); if (vid == value_id){ found = true; // make sure it's not a read only prop if (Manager::Get()->IsValueReadOnly(v)){ error_msg = "This is a read only property"; } else { bool bool_new_value; uint8 int8_new_value; int16 int16_new_value; int32 int32_new_value; switch (v.GetType()){ case ValueID::ValueType::ValueType_Bool: if ( new_value == "" || new_value == "0" || boost::iequals(new_value, "false") || boost::iequals(new_value, "off") || boost::iequals(new_value, "no") ){ bool_new_value = false; } else { bool_new_value = true; } success = Manager::Get()->SetValue(v, bool_new_value); if (!success){ error_msg = "Call to ZWave library SetValue failed"; } break; case ValueID::ValueType::ValueType_Byte: try { int8_new_value = (uint8)(boost::lexical_cast<int>(new_value)); success = Manager::Get()->SetValue(v, int8_new_value); if (!success){ error_msg = "Call to ZWave library SetValue failed"; } } catch (boost::bad_lexical_cast const&) { error_msg = "Type required is byte (number from 0 to 255); could not convert new_value to byte"; } break; case ValueID::ValueType::ValueType_Short: try { int16_new_value = boost::lexical_cast<int16>(new_value); success = Manager::Get()->SetValue(v, int16_new_value); if (!success){ error_msg = "Call to ZWave library SetValue failed"; } } catch (boost::bad_lexical_cast const&) { error_msg = "Type required is short (number from 0 to 65,535); could not convert new_value to short"; } break; case ValueID::ValueType::ValueType_Decimal: case ValueID::ValueType::ValueType_Int: try { int32_new_value = boost::lexical_cast<int32>(new_value); success = Manager::Get()->SetValue(v, int32_new_value); if (!success){ error_msg = "Call to ZWave library SetValue failed"; } } catch (boost::bad_lexical_cast const&) { error_msg = "Type required is int32 (number from 0 to 4,294,967,295); could not convert new_value to int32"; } break; case ValueID::ValueType::ValueType_Schedule: error_msg = "No support for setting 'schedule' value types yet"; break; case ValueID::ValueType::ValueType_List: case ValueID::ValueType::ValueType_String: case ValueID::ValueType::ValueType_Button: case ValueID::ValueType::ValueType_Raw: success = Manager::Get()->SetValue(v, new_value); if (!success){ error_msg = "Call to ZWave library SetValue failed"; } break; default: error_msg = "Value is an unknown type, could not set"; } } break; } } } LeaveCriticalSection(&g_criticalSection); if (!found){ error_msg = "Value id " + to_string(value_id) + " could not be found"; } return success; }
// Callback that is triggered when a value, group or node changes void ZWaveController::OnNotification(Notification const* _notification, void* _context){ // Must do this inside a critical section to avoid conflicts with the main thread EnterCriticalSection(&g_criticalSection); switch (_notification->GetType()) { case Notification::Type_ValueAdded: { if (NodeInfo* nodeInfo = GetNodeInfo(_notification)) { // Add the new value to our list nodeInfo->m_values.push_back(_notification->GetValueID()); ValueID v = _notification->GetValueID(); Logger::LogNotice("added value id " + to_string(v.GetId()) + " to node " + to_string(v.GetNodeId()) ); if (!ZWaveController::init_failed && ZWaveController::initial_node_queries_complete){ if (ZWaveController::ExposeValue(v)){ uint64 vid = v.GetId(); ValueChange::add_change(vid); } } } break; } case Notification::Type_ValueRemoved: { if (NodeInfo* nodeInfo = GetNodeInfo(_notification)) { // Remove the value from out list for (list<ValueID>::iterator it = nodeInfo->m_values.begin(); it != nodeInfo->m_values.end(); ++it) { if (!ZWaveController::init_failed && ZWaveController::initial_node_queries_complete){ ValueID v = *it; uint64 vid = v.GetId(); ValueChange::remove_change(vid); } if ((*it) == _notification->GetValueID()) { nodeInfo->m_values.erase(it); break; } } } break; } case Notification::Type_ValueChanged: { // One of the node values has changed if (NodeInfo* nodeInfo = GetNodeInfo(_notification)) { if (!ZWaveController::init_failed && ZWaveController::initial_node_queries_complete){ // the value that changed ValueID v = _notification->GetValueID(); string new_val; Manager::Get()->GetValueAsString(v, &new_val); Logger::LogNotice("node " + to_string(v.GetNodeId()) + ", value " + to_string(v.GetId()) + " (" + Manager::Get()->GetValueLabel(v) + "), has been changed to " + new_val); ValueChange::remove_expired_value_changes(); // first remove this value from the change queue if it's already in there if (ZWaveController::ExposeValue(v)){ string new_value; Manager::Get()->GetValueAsString(v, &new_value); uint64 vid = v.GetId(); ValueChange::remove_change(vid); ValueChange::add_change(vid); } } } break; } case Notification::Type_Group: { // One of the node's association groups has changed if (NodeInfo* nodeInfo = GetNodeInfo(_notification)) { nodeInfo = nodeInfo; // placeholder for real action } break; } case Notification::Type_NodeAdded: { // Add the new node to our list NodeInfo* nodeInfo = new NodeInfo(); nodeInfo->m_homeId = _notification->GetHomeId(); nodeInfo->m_nodeId = _notification->GetNodeId(); nodeInfo->m_polled = false; g_nodes.push_back(nodeInfo); Logger::LogNotice("node " + to_string(nodeInfo->m_nodeId) + " added"); break; } case Notification::Type_NodeRemoved: { // Remove the node from our list uint32 const homeId = _notification->GetHomeId(); uint8 const nodeId = _notification->GetNodeId(); for (list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it) { NodeInfo* nodeInfo = *it; if ((nodeInfo->m_homeId == homeId) && (nodeInfo->m_nodeId == nodeId)) { g_nodes.erase(it); Logger::LogNotice("node " + to_string(nodeInfo->m_nodeId) + " removed"); delete nodeInfo; break; } } break; } case Notification::Type_NodeEvent: { // We have received an event from the node, caused by a // basic_set or hail message. if (NodeInfo* nodeInfo = GetNodeInfo(_notification)) { if (nodeInfo->m_nodeId == 5 || nodeInfo->m_nodeId == 6){ Logger::LogNotice("node event received from node id " + to_string(nodeInfo->m_nodeId)); } else { Logger::LogNotice("node event received from node id " + to_string(nodeInfo->m_nodeId)); } } break; } case Notification::Type_PollingDisabled: { if (NodeInfo* nodeInfo = GetNodeInfo(_notification)) { nodeInfo->m_polled = false; } break; } case Notification::Type_PollingEnabled: { if (NodeInfo* nodeInfo = GetNodeInfo(_notification)) { nodeInfo->m_polled = true; } break; } case Notification::Type_DriverReady: { ZWaveController::homeId = _notification->GetHomeId(); Logger::LogNotice("controller driver is ready"); break; } case Notification::Type_DriverFailed: { ZWaveController::init_failed = true; Logger::LogNotice("controller initialization failed. make sure another program is not already controlling the controller"); break; } case Notification::Type_AwakeNodesQueried: case Notification::Type_AllNodesQueried: case Notification::Type_AllNodesQueriedSomeDead: { ZWaveController::initial_node_queries_complete = true; Logger::LogNotice("all zwave node queries complete"); break; } case Notification::Type_NodeQueriesComplete: { Logger::LogNotice("node " + to_string(_notification->GetNodeId()) + " queries complete"); break; } case Notification::Type_DriverReset: case Notification::Type_NodeNaming: case Notification::Type_NodeProtocolInfo: default: { // Logger::LogNotice("node " + to_string(_notification->GetNodeId()) + ""); } } // end of switch LeaveCriticalSection(&g_criticalSection); }
json_spirit::Object ZWaveController::GetValueInfo(ValueID v){ int home_id = (int)v.GetHomeId(); int node_id = (int)v.GetNodeId(); string product_name = Manager::Get()->GetNodeProductName(home_id, node_id); string product_id = Manager::Get()->GetNodeProductId(home_id, node_id); string product_type = Manager::Get()->GetNodeProductType(home_id, node_id); string node_type = Manager::Get()->GetNodeType(home_id, node_id); json_spirit::Object prop_info; prop_info.push_back(json_spirit::Pair("node_id", node_id)); prop_info.push_back(json_spirit::Pair("node_type", node_type)); prop_info.push_back(json_spirit::Pair("product_name", product_name)); prop_info.push_back(json_spirit::Pair("product_id", product_id)); prop_info.push_back(json_spirit::Pair("product_type", product_type)); uint64 vid = v.GetId(); string s_vid = boost::lexical_cast<string>(vid); prop_info.push_back(json_spirit::Pair("value_id", s_vid)); prop_info.push_back(json_spirit::Pair("label", Manager::Get()->GetValueLabel(v))); prop_info.push_back(json_spirit::Pair("help_text", Manager::Get()->GetValueHelp(v))); bool bool_prop_value; uint8 int8_prop_value; int32 int32_prop_value; string s_int32_prop_value; int16 int16_prop_value; string str_prop_value; switch (v.GetType()){ case ValueID::ValueType::ValueType_Bool: prop_info.push_back(json_spirit::Pair("type", "bool")); prop_info.push_back(json_spirit::Pair("type_help", "0/1, true/false, on/off")); Manager::Get()->GetValueAsBool(v, &bool_prop_value); prop_info.push_back(json_spirit::Pair("value", bool_prop_value)); break; case ValueID::ValueType::ValueType_Byte: prop_info.push_back(json_spirit::Pair("type", "byte")); prop_info.push_back(json_spirit::Pair("type_help", "number from 0 to 255")); Manager::Get()->GetValueAsByte(v, &int8_prop_value); prop_info.push_back(json_spirit::Pair("value", int8_prop_value)); break; case ValueID::ValueType::ValueType_Short: prop_info.push_back(json_spirit::Pair("type", "short")); prop_info.push_back(json_spirit::Pair("type_help", "number from 0 to 65,535")); Manager::Get()->GetValueAsShort(v, &int16_prop_value); prop_info.push_back(json_spirit::Pair("value", int16_prop_value)); break; case ValueID::ValueType::ValueType_Decimal: case ValueID::ValueType::ValueType_Int: prop_info.push_back(json_spirit::Pair("type", "int32")); prop_info.push_back(json_spirit::Pair("type_help", "number from 0 to 4,294,967,295")); Manager::Get()->GetValueAsInt(v, &int32_prop_value); // do all this checking below because of a bug in openzwave: https://code.google.com/p/open-zwave/issues/detail?id=382 s_int32_prop_value = boost::lexical_cast<string>(int32_prop_value); Manager::Get()->GetValueAsString(v, &str_prop_value); if (boost::iequals(s_int32_prop_value, str_prop_value)){ // bug did not happen prop_info.push_back(json_spirit::Pair("value", int32_prop_value)); } else { // bug DID happen prop_info.push_back(json_spirit::Pair("value", str_prop_value)); } break; case ValueID::ValueType::ValueType_List: { prop_info.push_back(json_spirit::Pair("type", "list")); prop_info.push_back(json_spirit::Pair("type_help", "list")); Manager::Get()->GetValueAsString(v, &str_prop_value); prop_info.push_back(json_spirit::Pair("value", str_prop_value)); std::vector<string> list_options; Manager::Get()->GetValueListItems(v, &list_options); std::vector<json_spirit::Value> values; for (std::vector<string>::iterator i = list_options.begin(); i != list_options.end(); ++i){ string opt = *i; values.push_back(opt); } prop_info.push_back(json_spirit::Pair("list_options", values)); break; } case ValueID::ValueType::ValueType_Schedule: prop_info.push_back(json_spirit::Pair("type", "schedule")); prop_info.push_back(json_spirit::Pair("type_help", "schedule")); Manager::Get()->GetValueAsString(v, &str_prop_value); prop_info.push_back(json_spirit::Pair("value", str_prop_value)); break; case ValueID::ValueType::ValueType_String: prop_info.push_back(json_spirit::Pair("type", "string")); prop_info.push_back(json_spirit::Pair("type_help", "string")); Manager::Get()->GetValueAsString(v, &str_prop_value); prop_info.push_back(json_spirit::Pair("value", str_prop_value)); break; case ValueID::ValueType::ValueType_Button: prop_info.push_back(json_spirit::Pair("type", "button")); prop_info.push_back(json_spirit::Pair("type_help", "button (string)")); Manager::Get()->GetValueAsString(v, &str_prop_value); prop_info.push_back(json_spirit::Pair("value", str_prop_value)); break; case ValueID::ValueType::ValueType_Raw: prop_info.push_back(json_spirit::Pair("type", "raw")); prop_info.push_back(json_spirit::Pair("type_help", "raw (string)")); Manager::Get()->GetValueAsString(v, &str_prop_value); prop_info.push_back(json_spirit::Pair("value", str_prop_value)); break; default: prop_info.push_back(json_spirit::Pair("type", "unknown")); prop_info.push_back(json_spirit::Pair("type_help", "unknown")); prop_info.push_back(json_spirit::Pair("value", "")); break; } Manager::Get()->GetValueAsString(v, &str_prop_value); prop_info.push_back(json_spirit::Pair("string value", str_prop_value)); prop_info.push_back(json_spirit::Pair("max", Manager::Get()->GetValueMax(v))); prop_info.push_back(json_spirit::Pair("min", Manager::Get()->GetValueMin(v))); prop_info.push_back(json_spirit::Pair("units", Manager::Get()->GetValueUnits(v))); prop_info.push_back(json_spirit::Pair("is_polled", Manager::Get()->IsValuePolled(v))); prop_info.push_back(json_spirit::Pair("read_only", Manager::Get()->IsValueReadOnly(v))); prop_info.push_back(json_spirit::Pair("write_only", Manager::Get()->IsValueWriteOnly(v))); prop_info.push_back(json_spirit::Pair("has_been_set", Manager::Get()->IsValueSet(v))); switch (v.GetGenre()){ case ValueID::ValueGenre::ValueGenre_Basic: prop_info.push_back(json_spirit::Pair("genre", "basic")); break; case ValueID::ValueGenre::ValueGenre_User: prop_info.push_back(json_spirit::Pair("genre", "user")); break; case ValueID::ValueGenre::ValueGenre_Config: prop_info.push_back(json_spirit::Pair("genre", "config")); break; case ValueID::ValueGenre::ValueGenre_System: prop_info.push_back(json_spirit::Pair("genre", "system")); break; case ValueID::ValueGenre::ValueGenre_Count: prop_info.push_back(json_spirit::Pair("genre", "count")); break; default: prop_info.push_back(json_spirit::Pair("genre", "unknown")); break; } return prop_info; }
//----------------------------------------------------------------------------- // <main> // Create the driver and then wait //----------------------------------------------------------------------------- int main( int argc, char* argv[] ) { pthread_mutexattr_t mutexattr; pthread_mutexattr_init ( &mutexattr ); pthread_mutexattr_settype( &mutexattr, PTHREAD_MUTEX_RECURSIVE ); pthread_mutex_init( &g_criticalSection, &mutexattr ); pthread_mutexattr_destroy( &mutexattr ); pthread_mutex_lock( &initMutex ); printf("Starting MinOZW with OpenZWave Version %s\n", Manager::getVersionAsString().c_str()); // Create the OpenZWave Manager. // The first argument is the path to the config files (where the manufacturer_specific.xml file is located // The second argument is the path for saved Z-Wave network state and the log file. If you leave it NULL // the log file will appear in the program's working directory. Options::Create( "../../../config/", "", "" ); Options::Get()->AddOptionInt( "SaveLogLevel", LogLevel_Detail ); Options::Get()->AddOptionInt( "QueueLogLevel", LogLevel_Debug ); Options::Get()->AddOptionInt( "DumpTrigger", LogLevel_Error ); Options::Get()->AddOptionInt( "PollInterval", 500 ); Options::Get()->AddOptionBool( "IntervalBetweenPolls", true ); Options::Get()->AddOptionBool("ValidateValueChanges", true); Options::Get()->Lock(); Manager::Create(); // Add a callback handler to the manager. The second argument is a context that // is passed to the OnNotification method. If the OnNotification is a method of // a class, the context would usually be a pointer to that class object, to // avoid the need for the notification handler to be a static. Manager::Get()->AddWatcher( OnNotification, NULL ); // Add a Z-Wave Driver // Modify this line to set the correct serial port for your PC interface. #ifdef DARWIN string port = "/dev/cu.usbserial"; #elif WIN32 string port = "\\\\.\\COM6"; #else string port = "/dev/ttyUSB0"; #endif if ( argc > 1 ) { port = argv[1]; } if( strcasecmp( port.c_str(), "usb" ) == 0 ) { Manager::Get()->AddDriver( "HID Controller", Driver::ControllerInterface_Hid ); } else { Manager::Get()->AddDriver( port ); } // Now we just wait for either the AwakeNodesQueried or AllNodesQueried notification, // then write out the config file. // In a normal app, we would be handling notifications and building a UI for the user. pthread_cond_wait( &initCond, &initMutex ); // Since the configuration file contains command class information that is only // known after the nodes on the network are queried, wait until all of the nodes // on the network have been queried (at least the "listening" ones) before // writing the configuration file. (Maybe write again after sleeping nodes have // been queried as well.) if( !g_initFailed ) { // The section below demonstrates setting up polling for a variable. In this simple // example, it has been hardwired to poll COMMAND_CLASS_BASIC on the each node that // supports this setting. pthread_mutex_lock( &g_criticalSection ); for( list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it ) { NodeInfo* nodeInfo = *it; // skip the controller (most likely node 1) if( nodeInfo->m_nodeId == 1) continue; printf("NodeID: %d \n ", nodeInfo->m_nodeId); printf("\t NodeName: %s \n ", Manager::Get()->GetNodeName(nodeInfo->m_homeId,nodeInfo->m_nodeId).c_str()); printf("\t ManufacturerName: %s \n ", Manager::Get()->GetNodeManufacturerName(nodeInfo->m_homeId,nodeInfo->m_nodeId).c_str()); printf("\t NodeProductName: %s \n ", Manager::Get()->GetNodeProductName(nodeInfo->m_homeId,nodeInfo->m_nodeId).c_str()); printf("Values announced by the nodes without polling: \n"); for( list<ValueID>::iterator it2 = nodeInfo->m_values.begin(); it2 != nodeInfo->m_values.end(); ++it2 ) { ValueID v = *it2; printf("\t ValueLabel: %s \n", Manager::Get()->GetValueLabel(v).c_str()); printf("\t\t ValueType: %d \n", v.GetType()); printf("\t\t ValueHelp: %s \n", Manager::Get()->GetValueHelp(v).c_str()); printf("\t\t ValueUnits: %s \n", Manager::Get()->GetValueUnits(v).c_str()); printf("\t\t ValueMin: %d \n", Manager::Get()->GetValueMin(v)); printf("\t\t ValueMax: %d \n", Manager::Get()->GetValueMax(v)); if( v.GetCommandClassId() == COMMAND_CLASS_BASIC ) { // Manager::Get()->EnablePoll( v, 2 ); // enables polling with "intensity" of 2, though this is irrelevant with only one value polled break; } } } pthread_mutex_unlock( &g_criticalSection ); // If we want to access our NodeInfo list, that has been built from all the // notification callbacks we received from the library, we have to do so // from inside a Critical Section. This is because the callbacks occur on other // threads, and we cannot risk the list being changed while we are using it. // We must hold the critical section for as short a time as possible, to avoid // stalling the OpenZWave drivers. // At this point, the program just waits for 3 minutes (to demonstrate polling), // then exits for( int i = 0; i < 60*3; i++ ) { pthread_mutex_lock( &g_criticalSection ); // but NodeInfo list and similar data should be inside critical section pthread_mutex_unlock( &g_criticalSection ); sleep(1); } Driver::DriverData data; Manager::Get()->GetDriverStatistics( g_homeId, &data ); printf("SOF: %d ACK Waiting: %d Read Aborts: %d Bad Checksums: %d\n", data.m_SOFCnt, data.m_ACKWaiting, data.m_readAborts, data.m_badChecksum); printf("Reads: %d Writes: %d CAN: %d NAK: %d ACK: %d Out of Frame: %d\n", data.m_readCnt, data.m_writeCnt, data.m_CANCnt, data.m_NAKCnt, data.m_ACKCnt, data.m_OOFCnt); printf("Dropped: %d Retries: %d\n", data.m_dropped, data.m_retries); } // program exit (clean up) if( strcasecmp( port.c_str(), "usb" ) == 0 ) { Manager::Get()->RemoveDriver( "HID Controller" ); } else { Manager::Get()->RemoveDriver( port ); } Manager::Get()->RemoveWatcher( OnNotification, NULL ); Manager::Destroy(); Options::Destroy(); pthread_mutex_destroy( &g_criticalSection ); return 0; }
//----------------------------------------------------------------------------- // <main> // Create the driver and then wait //----------------------------------------------------------------------------- int main( int argc, char* argv[] ) { InitializeCriticalSection( &g_criticalSection ); // Create the OpenZWave Manager. // The first argument is the path to the config files (where the manufacturer_specific.xml file is located // The second argument is the path for saved Z-Wave network state and the log file. If you leave it NULL // the log file will appear in the program's working directory. //Options::Create( "../../../../../../config/", "", "" ); Options::Create("C:/source/ideas/openzwave-1.0.791/config/", "", ""); Options::Get()->AddOptionInt( "SaveLogLevel", LogLevel_Detail ); Options::Get()->AddOptionInt( "QueueLogLevel", LogLevel_Debug ); Options::Get()->AddOptionInt( "DumpTrigger", LogLevel_Error ); Options::Get()->AddOptionInt( "PollInterval", 500 ); Options::Get()->AddOptionBool( "IntervalBetweenPolls", true ); Options::Get()->AddOptionBool("ValidateValueChanges", true); Options::Get()->Lock(); Manager::Create(); // Add a callback handler to the manager. The second argument is a context that // is passed to the OnNotification method. If the OnNotification is a method of // a class, the context would usually be a pointer to that class object, to // avoid the need for the notification handler to be a static. Manager::Get()->AddWatcher( OnNotification, NULL ); // Add a Z-Wave Driver // Modify this line to set the correct serial port for your PC interface. string port = "\\\\.\\COM4"; Manager::Get()->AddDriver( ( argc > 1 ) ? argv[1] : port ); //Manager::Get()->AddDriver( "HID Controller", Driver::ControllerInterface_Hid ); // Now we just wait for either the AwakeNodesQueried or AllNodesQueried notification, // then write out the config file. // In a normal app, we would be handling notifications and building a UI for the user. // Since the configuration file contains command class information that is only // known after the nodes on the network are queried, wait until all of the nodes // on the network have been queried (at least the "listening" ones) before // writing the configuration file. (Maybe write again after sleeping nodes have // been queried as well.) while( !g_nodesQueried ) { Sleep( 1000 ); } if( !g_initFailed ) { Manager::Get()->WriteConfig( g_homeId ); // The section below demonstrates setting up polling for a variable. In this simple // example, it has been hardwired to poll COMMAND_CLASS_BASIC on the each node that // supports this setting. EnterCriticalSection( &g_criticalSection ); for( list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it ) { NodeInfo* nodeInfo = *it; // skip the controller (most likely node 1) if( nodeInfo->m_nodeId == 1) continue; for( list<ValueID>::iterator it2 = nodeInfo->m_values.begin(); it2 != nodeInfo->m_values.end(); ++it2 ) { ValueID v = *it2; if( v.GetCommandClassId() == 0x20 ) { Manager::Get()->EnablePoll( v, 2 ); // enables polling with "intensity" of 2, though this is irrelevant with only one value polled break; } } } LeaveCriticalSection( &g_criticalSection ); // If we want to access our NodeInfo list, that has been built from all the // notification callbacks we received from the library, we have to do so // from inside a Critical Section. This is because the callbacks occur on other // threads, and we cannot risk the list being changed while we are using it. // We must hold the critical section for as short a time as possible, to avoid // stalling the OpenZWave drivers. // At this point, the program just waits for 3 minutes (to demonstrate polling), // then exits for( int i = 0; i < 60*3*10; i++ ) { Sleep(90); // do most of your work outside critical section EnterCriticalSection( &g_criticalSection ); Sleep(10); // but NodeInfo list and similar data should be inside critical section LeaveCriticalSection( &g_criticalSection ); } Driver::DriverData data; Manager::Get()->GetDriverStatistics( g_homeId, &data ); printf("SOF: %d ACK Waiting: %d Read Aborts: %d Bad Checksums: %d\n", data.m_SOFCnt, data.m_ACKWaiting, data.m_readAborts, data.m_badChecksum); printf("Reads: %d Writes: %d CAN: %d NAK: %d ACK: %d Out of Frame: %d\n", data.m_readCnt, data.m_writeCnt, data.m_CANCnt, data.m_NAKCnt, data.m_ACKCnt, data.m_OOFCnt); printf("Dropped: %d Retries: %d\n", data.m_dropped, data.m_retries); } // program exit (clean up) Manager::Destroy(); Options::Destroy(); DeleteCriticalSection( &g_criticalSection ); return 0; }
//----------------------------------------------------------------------------- // <OnNotification> // Callback that is triggered when a value, group or node changes //----------------------------------------------------------------------------- void OnNotification ( Notification const* _notification, void* _context ) { qpid::types::Variant::Map eventmap; // Must do this inside a critical section to avoid conflicts with the main thread pthread_mutex_lock( &g_criticalSection ); switch( _notification->GetType() ) { case Notification::Type_ValueAdded: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { // Add the new value to our list nodeInfo->m_values.push_back( _notification->GetValueID() ); uint8 basic = Manager::Get()->GetNodeBasic(_notification->GetHomeId(),_notification->GetNodeId()); uint8 generic = Manager::Get()->GetNodeGeneric(_notification->GetHomeId(),_notification->GetNodeId()); uint8 specific = Manager::Get()->GetNodeSpecific(_notification->GetHomeId(),_notification->GetNodeId()); ValueID id = _notification->GetValueID(); string label = Manager::Get()->GetValueLabel(id); stringstream tempstream; tempstream << (int) _notification->GetNodeId(); tempstream << "/"; tempstream << (int) id.GetInstance(); string nodeinstance = tempstream.str(); tempstream << "-"; tempstream << label; string tempstring = tempstream.str(); ZWaveNode *device; if (basic == BASIC_TYPE_CONTROLLER) { if ((device = devices.findId(nodeinstance)) != NULL) { device->addValue(label, id); device->setDevicetype("remote"); } else { device = new ZWaveNode(nodeinstance, "remote"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } } else switch(id.GetCommandClassId()) { case COMMAND_CLASS_SWITCH_MULTILEVEL: if (label == "Level") { if ((device = devices.findId(nodeinstance)) != NULL) { device->addValue(label, id); device->setDevicetype("dimmer"); } else { device = new ZWaveNode(nodeinstance, "dimmer"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } // Manager::Get()->EnablePoll(id); } break; case COMMAND_CLASS_SWITCH_BINARY: if (label == "Switch") { if ((device = devices.findId(nodeinstance)) != NULL) { device->addValue(label, id); } else { device = new ZWaveNode(nodeinstance, "switch"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } // Manager::Get()->EnablePoll(id); } break; case COMMAND_CLASS_SENSOR_BINARY: if (label == "Sensor") { if ((device = devices.findId(tempstring)) != NULL) { device->addValue(label, id); } else { device = new ZWaveNode(tempstring, "binarysensor"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } // Manager::Get()->EnablePoll(id); } break; case COMMAND_CLASS_SENSOR_MULTILEVEL: if (label == "Luminance") { device = new ZWaveNode(tempstring, "brightnesssensor"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } else if (label == "Temperature") { if (generic == GENERIC_TYPE_THERMOSTAT) { if ((device = devices.findId(nodeinstance)) != NULL) { device->addValue(label, id); } else { device = new ZWaveNode(nodeinstance, "thermostat"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } } else { device = new ZWaveNode(tempstring, "temperaturesensor"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } } else { printf("WARNING: unhandled label for SENSOR_MULTILEVEL: %s - adding generic multilevelsensor\n",label.c_str()); if ((device = devices.findId(nodeinstance)) != NULL) { device->addValue(label, id); } else { device = new ZWaveNode(nodeinstance, "multilevelsensor"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } } // Manager::Get()->EnablePoll(id); break; case COMMAND_CLASS_METER: if (label == "Power") { device = new ZWaveNode(tempstring, "powermeter"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } else if (label == "Energy") { device = new ZWaveNode(tempstring, "energymeter"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } else { printf("WARNING: unhandled label for CLASS_METER: %s - adding generic multilevelsensor\n",label.c_str()); if ((device = devices.findId(nodeinstance)) != NULL) { device->addValue(label, id); } else { device = new ZWaveNode(nodeinstance, "multilevelsensor"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } } // Manager::Get()->EnablePoll(id); break; case COMMAND_CLASS_BASIC_WINDOW_COVERING: // if (label == "Open") { if ((device = devices.findId(nodeinstance)) != NULL) { device->addValue(label, id); device->setDevicetype("drapes"); } else { device = new ZWaveNode(nodeinstance, "drapes"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } // Manager::Get()->EnablePoll(id); // } break; case COMMAND_CLASS_THERMOSTAT_SETPOINT: if (polling) Manager::Get()->EnablePoll(id); case COMMAND_CLASS_THERMOSTAT_MODE: case COMMAND_CLASS_THERMOSTAT_FAN_MODE: case COMMAND_CLASS_THERMOSTAT_FAN_STATE: case COMMAND_CLASS_THERMOSTAT_OPERATING_STATE: cout << "adding thermostat label: " << label << endl; if ((device = devices.findId(nodeinstance)) != NULL) { device->addValue(label, id); device->setDevicetype("thermostat"); } else { device = new ZWaveNode(nodeinstance, "thermostat"); device->addValue(label, id); devices.add(device); agoConnection->addDevice(device->getId().c_str(), device->getDevicetype().c_str()); } break; default: printf("Notification: Unassigned Value Added Home 0x%08x Node %d Genre %d Class %x Instance %d Index %d Type %d - Label: %s\n", _notification->GetHomeId(), _notification->GetNodeId(), id.GetGenre(), id.GetCommandClassId(), id.GetInstance(), id.GetIndex(), id.GetType(),label.c_str()); // printf("Notification: Unassigned Value Added Home 0x%08x Node %d Genre %d Class %x Instance %d Index %d Type %d - ID: %" PRIu64 "\n", _notification->GetHomeId(), _notification->GetNodeId(), id.GetGenre(), id.GetCommandClassId(), id.GetInstance(), id.GetIndex(), id.GetType(),id.GetId()); } } break; } case Notification::Type_ValueRemoved: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { // Remove the value from out list for( list<ValueID>::iterator it = nodeInfo->m_values.begin(); it != nodeInfo->m_values.end(); ++it ) { if( (*it) == _notification->GetValueID() ) { nodeInfo->m_values.erase( it ); break; } } } break; } case Notification::Type_ValueChanged: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { // One of the node values has changed // TBD... // nodeInfo = nodeInfo; ValueID id = _notification->GetValueID(); string str; printf("Notification: Value Changed Home 0x%08x Node %d Genre %d Class %d Instance %d Index %d Type %d\n", _notification->GetHomeId(), _notification->GetNodeId(), id.GetGenre(), id.GetCommandClassId(), id.GetInstance(), id.GetIndex(), id.GetType()); if (Manager::Get()->GetValueAsString(id, &str)) { qpid::types::Variant cachedValue; cachedValue.parse(str); valueCache[id] = cachedValue; string label = Manager::Get()->GetValueLabel(id); string units = Manager::Get()->GetValueUnits(id); // TODO: send proper types and don't convert everything to string string level = str; string eventtype = ""; if (str == "True") level="255"; if (str == "False") level="0"; printf("Value: %s Label: %s Unit: %s\n",str.c_str(),label.c_str(),units.c_str()); if ((label == "Basic") || (label == "Switch") || (label == "Level")) { eventtype="event.device.statechanged"; } if (label == "Luminance") { eventtype="event.environment.brightnesschanged"; } if (label == "Temperature") { eventtype="event.environment.temperaturechanged"; if (units=="F" && unitsystem==0) { units="C"; str = float2str((atof(str.c_str())-32)*5/9); level = str; } else if (units =="C" && unitsystem==1) { units="F"; str = float2str(atof(str.c_str())*9/5 + 32); level = str; } } if (label == "Relative Humidity") { eventtype="event.environment.humiditychanged"; } if (label == "Battery Level") { eventtype="event.device.batterylevelchanged"; } if (label == "Alarm Level") { eventtype="event.security.alarmlevelchanged"; } if (label == "Alarm Type") { eventtype="event.security.alarmtypechanged"; } if (label == "Sensor") { eventtype="event.security.sensortriggered"; } if (label == "Energy") { eventtype="event.environment.energychanged"; } if (label == "Power") { eventtype="event.environment.powerchanged"; } if (label == "Mode") { eventtype="event.environment.modechanged"; } if (label == "Fan Mode") { eventtype="event.environment.fanmodechanged"; } if (label == "Fan State") { eventtype="event.environment.fanstatechanged"; } if (label == "Operating State") { eventtype="event.environment.operatingstatechanged"; } if (label == "Cooling 1") { eventtype="event.environment.coolsetpointchanged"; } if (label == "Heating 1") { eventtype="event.environment.heatsetpointchanged"; } if (label == "Fan State") { eventtype="event.environment.fanstatechanged"; } if (eventtype != "") { ZWaveNode *device = devices.findValue(id); if (device != NULL) { if (debug) printf("Sending %s event from child %s\n",eventtype.c_str(), device->getId().c_str()); agoConnection->emitEvent(device->getId().c_str(), eventtype.c_str(), level.c_str(), units.c_str()); } } } } break; } case Notification::Type_Group: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { // One of the node's association groups has changed // TBD... nodeInfo = nodeInfo; eventmap["description"]="Node association added"; eventmap["state"]="associationchanged"; eventmap["nodeid"] = _notification->GetNodeId(); eventmap["homeid"] = _notification->GetHomeId(); agoConnection->emitEvent("zwavecontroller", "event.zwave.associationchanged", eventmap); } break; } case Notification::Type_NodeAdded: { // Add the new node to our list NodeInfo* nodeInfo = new NodeInfo(); nodeInfo->m_homeId = _notification->GetHomeId(); nodeInfo->m_nodeId = _notification->GetNodeId(); nodeInfo->m_polled = false; g_nodes.push_back( nodeInfo ); // todo: announce node eventmap["description"]="Node added"; eventmap["state"]="nodeadded"; eventmap["nodeid"] = _notification->GetNodeId(); eventmap["homeid"] = _notification->GetHomeId(); agoConnection->emitEvent("zwavecontroller", "event.zwave.networkchanged", eventmap); break; } case Notification::Type_NodeRemoved: { // Remove the node from our list uint32 const homeId = _notification->GetHomeId(); uint8 const nodeId = _notification->GetNodeId(); eventmap["description"]="Node removed"; eventmap["state"]="noderemoved"; eventmap["nodeid"] = _notification->GetNodeId(); eventmap["homeid"] = _notification->GetHomeId(); agoConnection->emitEvent("zwavecontroller", "event.zwave.networkchanged", eventmap); for( list<NodeInfo*>::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it ) { NodeInfo* nodeInfo = *it; if( ( nodeInfo->m_homeId == homeId ) && ( nodeInfo->m_nodeId == nodeId ) ) { g_nodes.erase( it ); break; } } break; } case Notification::Type_NodeEvent: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { // We have received an event from the node, caused by a // basic_set or hail message. ValueID id = _notification->GetValueID(); string label = Manager::Get()->GetValueLabel(id); stringstream level; level << (int) _notification->GetByte(); string eventtype = "event.device.statechanged"; ZWaveNode *device = devices.findValue(id); if (device != NULL) { if (debug) printf("Sending %s event from child %s\n",eventtype.c_str(), device->getId().c_str()); agoConnection->emitEvent(device->getId().c_str(), eventtype.c_str(), level.str().c_str(), ""); } else { cout << "no agocontrol device found for node event - Label: " << label << " Level: " << level << endl; } } break; } case Notification::Type_SceneEvent: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { int scene = _notification->GetSceneId(); ValueID id = _notification->GetValueID(); string label = Manager::Get()->GetValueLabel(id); stringstream tempstream; tempstream << (int) _notification->GetNodeId(); tempstream << "/1"; string nodeinstance = tempstream.str(); string eventtype = "event.device.statechanged"; ZWaveNode *device; if ((device = devices.findId(nodeinstance)) != NULL) { if (debug) printf("Sending %s for scene %d event from child %s\n", eventtype.c_str(), scene, device->getId().c_str()); agoConnection->emitEvent(device->getId().c_str(), eventtype.c_str(), scene, ""); } else { cout << "WARNING: no agocontrol device found for scene event" << endl; cout << "Node: " << nodeinstance << " Scene: " << scene << endl; } } break; } case Notification::Type_PollingDisabled: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { nodeInfo->m_polled = false; } break; } case Notification::Type_PollingEnabled: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { nodeInfo->m_polled = true; } break; } case Notification::Type_DriverReady: { g_homeId = _notification->GetHomeId(); break; } case Notification::Type_DriverFailed: { g_initFailed = true; pthread_cond_broadcast(&initCond); break; } case Notification::Type_AwakeNodesQueried: case Notification::Type_AllNodesQueried: case Notification::Type_AllNodesQueriedSomeDead: { pthread_cond_broadcast(&initCond); break; } case Notification::Type_DriverReset: case Notification::Type_Notification: case Notification::Type_NodeNaming: case Notification::Type_NodeProtocolInfo: case Notification::Type_NodeQueriesComplete: case Notification::Type_EssentialNodeQueriesComplete: { break; } default: { cout << "WARNING: Unhandled OpenZWave Event: " << _notification->GetType() << endl; } } pthread_mutex_unlock( &g_criticalSection ); }