diff --git a/src/openzwave.cc b/src/openzwave.cc index 0939480..6234dea 100644 --- a/src/openzwave.cc +++ b/src/openzwave.cc @@ -15,12 +15,14 @@ */ #include +#include #include #include #include -#include #include +#include +#include #include "Manager.h" #include "Node.h" @@ -32,21 +34,20 @@ using namespace v8; using namespace node; namespace { - -struct OZW: ObjectWrap { - static Handle New(const Arguments& args); - static Handle Connect(const Arguments& args); - static Handle Disconnect(const Arguments& args); - static Handle SetValue(const Arguments& args); - static Handle SetLevel(const Arguments& args); - static Handle SetLocation(const Arguments& args); - static Handle SetName(const Arguments& args); - static Handle SwitchOn(const Arguments& args); - static Handle SwitchOff(const Arguments& args); - static Handle EnablePoll(const Arguments& args); - static Handle DisablePoll(const Arguments& args); - static Handle HardReset(const Arguments& args); - static Handle SoftReset(const Arguments& args); +struct OZW : node::ObjectWrap { + static void New(const FunctionCallbackInfo& args); + static void Connect(const FunctionCallbackInfo& args); + static void Disconnect(const FunctionCallbackInfo& args); + static void SetValue(const FunctionCallbackInfo& args); + static void SetLevel(const FunctionCallbackInfo& args); + static void SetLocation(const FunctionCallbackInfo& args); + static void SetName(const FunctionCallbackInfo& args); + static void SwitchOn(const FunctionCallbackInfo& args); + static void SwitchOff(const FunctionCallbackInfo& args); + static void EnablePoll(const FunctionCallbackInfo& args); + static void DisablePoll(const FunctionCallbackInfo& args); + static void HardReset(const FunctionCallbackInfo& args); + static void SoftReset(const FunctionCallbackInfo& args); }; Persistent context_obj; @@ -54,22 +55,22 @@ Persistent context_obj; uv_async_t async; typedef struct { - uint32_t type; - uint32_t homeid; - uint8_t nodeid; - uint8_t groupidx; - uint8_t event; - uint8_t buttonid; - uint8_t sceneid; - uint8_t notification; - std::list values; + uint32_t type; + uint32_t homeid; + uint8_t nodeid; + uint8_t groupidx; + uint8_t event; + uint8_t buttonid; + uint8_t sceneid; + uint8_t notification; + std::list values; } NotifInfo; typedef struct { - uint32_t homeid; - uint8_t nodeid; - bool polled; - std::list values; + uint32_t homeid; + uint8_t nodeid; + bool polled; + std::list values; } NodeInfo; /* @@ -91,16 +92,16 @@ static uint32_t homeid; */ NodeInfo *get_node_info(uint8_t nodeid) { - std::list::iterator it; - NodeInfo *node; + std::list::iterator it; + NodeInfo *node; - for (it = znodes.begin(); it != znodes.end(); ++it) { - node = *it; - if (node->nodeid == nodeid) - return node; - } + for (it = znodes.begin(); it != znodes.end(); ++it) { + node = *it; + if (node->nodeid == nodeid) + return node; + } - return NULL; + return NULL; } /* @@ -109,493 +110,507 @@ NodeInfo *get_node_info(uint8_t nodeid) */ void cb(OpenZWave::Notification const *cb, void *ctx) { - NotifInfo *notif = new NotifInfo(); - - notif->type = cb->GetType(); - notif->homeid = cb->GetHomeId(); - notif->nodeid = cb->GetNodeId(); - notif->values.push_front(cb->GetValueID()); - - /* - * Some values are only set on particular notifications, and - * assertions in openzwave prevent us from trying to fetch them - * unconditionally. - */ - switch (notif->type) { - case OpenZWave::Notification::Type_Group: - notif->groupidx = cb->GetGroupIdx(); - break; - case OpenZWave::Notification::Type_NodeEvent: - notif->event = cb->GetEvent(); - break; - case OpenZWave::Notification::Type_CreateButton: - case OpenZWave::Notification::Type_DeleteButton: - case OpenZWave::Notification::Type_ButtonOn: - case OpenZWave::Notification::Type_ButtonOff: - notif->buttonid = cb->GetButtonId(); - break; - case OpenZWave::Notification::Type_SceneEvent: - notif->sceneid = cb->GetSceneId(); - break; - case OpenZWave::Notification::Type_Notification: - notif->notification = cb->GetNotification(); - break; - } - - pthread_mutex_lock(&zqueue_mutex); - zqueue.push(notif); - pthread_mutex_unlock(&zqueue_mutex); - - uv_async_send(&async); + NotifInfo *notif = new NotifInfo(); + + notif->type = cb->GetType(); + notif->homeid = cb->GetHomeId(); + notif->nodeid = cb->GetNodeId(); + notif->values.push_front(cb->GetValueID()); + + /* + * Some values are only set on particular notifications, and + * assertions in openzwave prevent us from trying to fetch them + * unconditionally. + */ + switch (notif->type) { + case OpenZWave::Notification::Type_Group: + notif->groupidx = cb->GetGroupIdx(); + break; + case OpenZWave::Notification::Type_NodeEvent: + notif->event = cb->GetEvent(); + break; + case OpenZWave::Notification::Type_CreateButton: + case OpenZWave::Notification::Type_DeleteButton: + case OpenZWave::Notification::Type_ButtonOn: + case OpenZWave::Notification::Type_ButtonOff: + notif->buttonid = cb->GetButtonId(); + break; + case OpenZWave::Notification::Type_SceneEvent: + notif->sceneid = cb->GetSceneId(); + break; + case OpenZWave::Notification::Type_Notification: + notif->notification = cb->GetNotification(); + break; + } + + pthread_mutex_lock(&zqueue_mutex); + zqueue.push(notif); + pthread_mutex_unlock(&zqueue_mutex); + + uv_async_send(&async); } /* * Async handler, triggered by the OpenZWave callback. */ -void async_cb_handler(uv_async_t *handle, int status) +void async_cb_handler(uv_async_t *handle) { - NodeInfo *node; - NotifInfo *notif; - Local args[16]; - - pthread_mutex_lock(&zqueue_mutex); - - while (!zqueue.empty()) - { - notif = zqueue.front(); - - switch (notif->type) { - case OpenZWave::Notification::Type_DriverReady: - homeid = notif->homeid; - args[0] = String::New("driver ready"); - args[1] = Integer::New(homeid); - MakeCallback(context_obj, "emit", 2, args); - break; - case OpenZWave::Notification::Type_DriverFailed: - args[0] = String::New("driver failed"); - MakeCallback(context_obj, "emit", 1, args); - break; - /* - * NodeNew is triggered when a node is discovered which is not - * found in the OpenZWave XML file. As we do not use that file - * simply ignore those notifications for now. - * - * NodeAdded is when we actually have a new node to set up. - */ - case OpenZWave::Notification::Type_NodeNew: - break; - case OpenZWave::Notification::Type_NodeAdded: - node = new NodeInfo(); - node->homeid = notif->homeid; - node->nodeid = notif->nodeid; - node->polled = false; - pthread_mutex_lock(&znodes_mutex); - znodes.push_back(node); - pthread_mutex_unlock(&znodes_mutex); - args[0] = String::New("node added"); - args[1] = Integer::New(notif->nodeid); - MakeCallback(context_obj, "emit", 2, args); - break; - /* - * Ignore intermediate notifications about a node status, we - * wait until the node is ready before retrieving information. - */ - case OpenZWave::Notification::Type_NodeProtocolInfo: - case OpenZWave::Notification::Type_NodeNaming: - // XXX: these should be supported correctly. - case OpenZWave::Notification::Type_PollingEnabled: - case OpenZWave::Notification::Type_PollingDisabled: - break; - /* - * Node values. - */ - case OpenZWave::Notification::Type_ValueAdded: - case OpenZWave::Notification::Type_ValueChanged: - { - OpenZWave::ValueID value = notif->values.front(); - Local valobj = Object::New(); - const char *evname = (notif->type == OpenZWave::Notification::Type_ValueAdded) - ? "value added" : "value changed"; - - if (notif->type == OpenZWave::Notification::Type_ValueAdded) { - if ((node = get_node_info(notif->nodeid))) { - pthread_mutex_lock(&znodes_mutex); - node->values.push_back(value); - pthread_mutex_unlock(&znodes_mutex); - } - OpenZWave::Manager::Get()->SetChangeVerified(value, true); - } - - /* - * Common value types. - */ - valobj->Set(String::NewSymbol("type"), - String::New(OpenZWave::Value::GetTypeNameFromEnum(value.GetType()))); - valobj->Set(String::NewSymbol("genre"), - String::New(OpenZWave::Value::GetGenreNameFromEnum(value.GetGenre()))); - valobj->Set(String::NewSymbol("instance"), - Integer::New(value.GetInstance())); - valobj->Set(String::NewSymbol("index"), - Integer::New(value.GetIndex())); - valobj->Set(String::NewSymbol("label"), - String::New(OpenZWave::Manager::Get()->GetValueLabel(value).c_str())); - valobj->Set(String::NewSymbol("units"), - String::New(OpenZWave::Manager::Get()->GetValueUnits(value).c_str())); - valobj->Set(String::NewSymbol("read_only"), - Boolean::New(OpenZWave::Manager::Get()->IsValueReadOnly(value))->ToBoolean()); - valobj->Set(String::NewSymbol("write_only"), - Boolean::New(OpenZWave::Manager::Get()->IsValueWriteOnly(value))->ToBoolean()); - // XXX: verify_changes= - // XXX: poll_intensity= - valobj->Set(String::NewSymbol("min"), - Integer::New(OpenZWave::Manager::Get()->GetValueMin(value))); - valobj->Set(String::NewSymbol("max"), - Integer::New(OpenZWave::Manager::Get()->GetValueMax(value))); - - /* - * The value itself is type-specific. - */ - switch (value.GetType()) { - case OpenZWave::ValueID::ValueType_Bool: - { - bool val; - OpenZWave::Manager::Get()->GetValueAsBool(value, &val); - valobj->Set(String::NewSymbol("value"), Boolean::New(val)->ToBoolean()); - break; - } - case OpenZWave::ValueID::ValueType_Byte: - { - uint8_t val; - OpenZWave::Manager::Get()->GetValueAsByte(value, &val); - valobj->Set(String::NewSymbol("value"), Integer::New(val)); - break; - } - case OpenZWave::ValueID::ValueType_Decimal: - { - float val; - OpenZWave::Manager::Get()->GetValueAsFloat(value, &val); - valobj->Set(String::NewSymbol("value"), Integer::New(val)); - break; - } - case OpenZWave::ValueID::ValueType_Int: - { - int32_t val; - OpenZWave::Manager::Get()->GetValueAsInt(value, &val); - valobj->Set(String::NewSymbol("value"), Integer::New(val)); - break; - } - case OpenZWave::ValueID::ValueType_List: - { - Local items; - } - case OpenZWave::ValueID::ValueType_Short: - { - int16_t val; - OpenZWave::Manager::Get()->GetValueAsShort(value, &val); - valobj->Set(String::NewSymbol("value"), Integer::New(val)); - break; - } - case OpenZWave::ValueID::ValueType_String: - { - std::string val; - OpenZWave::Manager::Get()->GetValueAsString(value, &val); - valobj->Set(String::NewSymbol("value"), String::New(val.c_str())); - break; - } - /* - * Buttons do not have a value. - */ - case OpenZWave::ValueID::ValueType_Button: - { - break; - } - default: - fprintf(stderr, "unsupported value type: 0x%x\n", value.GetType()); - break; - } - - args[0] = String::New(evname); - args[1] = Integer::New(notif->nodeid); - args[2] = Integer::New(value.GetCommandClassId()); - args[3] = valobj; - MakeCallback(context_obj, "emit", 4, args); - - break; - } - /* - * A value update was sent but nothing changed, likely due to - * the value just being polled. Ignore, as we handle actual - * changes above. - */ - case OpenZWave::Notification::Type_ValueRefreshed: - break; - case OpenZWave::Notification::Type_ValueRemoved: - { - OpenZWave::ValueID value = notif->values.front(); - std::list::iterator vit; - if ((node = get_node_info(notif->nodeid))) { - for (vit = node->values.begin(); vit != node->values.end(); ++vit) { - if ((*vit) == notif->values.front()) { - node->values.erase(vit); - break; - } - } - } - args[0] = String::New("value removed"); - args[1] = Integer::New(notif->nodeid); - args[2] = Integer::New(value.GetCommandClassId()); - args[3] = Integer::New(value.GetIndex()); - MakeCallback(context_obj, "emit", 4, args); - break; - } - /* - * I believe this means that the node is now ready to accept - * commands, however for now we will wait until all queries are - * complete before notifying upstack, just in case. - */ - case OpenZWave::Notification::Type_EssentialNodeQueriesComplete: - break; - /* - * The node is now fully ready for operation. - */ - case OpenZWave::Notification::Type_NodeQueriesComplete: - { - Local info = Object::New(); - info->Set(String::NewSymbol("manufacturer"), - String::New(OpenZWave::Manager::Get()->GetNodeManufacturerName(notif->homeid, notif->nodeid).c_str())); - info->Set(String::NewSymbol("manufacturerid"), - String::New(OpenZWave::Manager::Get()->GetNodeManufacturerId(notif->homeid, notif->nodeid).c_str())); - info->Set(String::NewSymbol("product"), - String::New(OpenZWave::Manager::Get()->GetNodeProductName(notif->homeid, notif->nodeid).c_str())); - info->Set(String::NewSymbol("producttype"), - String::New(OpenZWave::Manager::Get()->GetNodeProductType(notif->homeid, notif->nodeid).c_str())); - info->Set(String::NewSymbol("productid"), - String::New(OpenZWave::Manager::Get()->GetNodeProductId(notif->homeid, notif->nodeid).c_str())); - info->Set(String::NewSymbol("type"), - String::New(OpenZWave::Manager::Get()->GetNodeType(notif->homeid, notif->nodeid).c_str())); - info->Set(String::NewSymbol("name"), - String::New(OpenZWave::Manager::Get()->GetNodeName(notif->homeid, notif->nodeid).c_str())); - info->Set(String::NewSymbol("loc"), - String::New(OpenZWave::Manager::Get()->GetNodeLocation(notif->homeid, notif->nodeid).c_str())); - args[0] = String::New("node ready"); - args[1] = Integer::New(notif->nodeid); - args[2] = info; - MakeCallback(context_obj, "emit", 3, args); - break; - } - /* - * The network scan has been completed. Currently we do not - * care about dead nodes - is there anything we can do anyway? - */ - case OpenZWave::Notification::Type_AwakeNodesQueried: - case OpenZWave::Notification::Type_AllNodesQueried: - case OpenZWave::Notification::Type_AllNodesQueriedSomeDead: - args[0] = String::New("scan complete"); - MakeCallback(context_obj, "emit", 1, args); - break; - /* - * A general notification. - */ - case OpenZWave::Notification::Type_Notification: - args[0] = String::New("notification"); - args[1] = Integer::New(notif->nodeid); - args[2] = Integer::New(notif->notification); - MakeCallback(context_obj, "emit", 3, args); - break; - /* - * Send unhandled events to stderr so we can monitor them if - * necessary. - */ - default: - fprintf(stderr, "Unhandled notification: %d\n", notif->type); - break; - } - - zqueue.pop(); - } - - pthread_mutex_unlock(&zqueue_mutex); + + Isolate* isolate = Isolate::GetCurrent(); + + NodeInfo *node; + NotifInfo *notif; + Local args[16]; + + pthread_mutex_lock(&zqueue_mutex); + + while (!zqueue.empty()) + { + notif = zqueue.front(); + + switch (notif->type) { + case OpenZWave::Notification::Type_DriverReady: + homeid = notif->homeid; + args[0] = String::NewFromUtf8(isolate, "driver ready"); + args[1] = Integer::New(isolate,homeid); + MakeCallback(isolate, Local::New(isolate, context_obj), "emit", 2, args); + break; + case OpenZWave::Notification::Type_DriverFailed: + args[0] = String::NewFromUtf8(isolate,"driver failed"); + MakeCallback(isolate, Local::New(isolate, context_obj), "emit", 1, args); + break; + /* + * NodeNew is triggered when a node is discovered which is not + * found in the OpenZWave XML file. As we do not use that file + * simply ignore those notifications for now. + * + * NodeAdded is when we actually have a new node to set up. + */ + case OpenZWave::Notification::Type_NodeNew: + break; + case OpenZWave::Notification::Type_NodeAdded: + node = new NodeInfo(); + node->homeid = notif->homeid; + node->nodeid = notif->nodeid; + node->polled = false; + pthread_mutex_lock(&znodes_mutex); + znodes.push_back(node); + pthread_mutex_unlock(&znodes_mutex); + args[0] = String::NewFromUtf8(isolate, "node added"); + args[1] = Integer::New(isolate,notif->nodeid); + MakeCallback(isolate, Local::New(isolate, context_obj), "emit", 2, args); + break; + /* + * Ignore intermediate notifications about a node status, we + * wait until the node is ready before retrieving information. + */ + case OpenZWave::Notification::Type_NodeProtocolInfo: + case OpenZWave::Notification::Type_NodeNaming: + // XXX: these should be supported correctly. + case OpenZWave::Notification::Type_PollingEnabled: + case OpenZWave::Notification::Type_PollingDisabled: + break; + /* + * Node values. + */ + case OpenZWave::Notification::Type_ValueAdded: + case OpenZWave::Notification::Type_ValueChanged: + { + OpenZWave::ValueID value = notif->values.front(); + Local valobj = Object::New(isolate); + const char *evname = (notif->type == OpenZWave::Notification::Type_ValueAdded) + ? "value added" : "value changed"; + + if (notif->type == OpenZWave::Notification::Type_ValueAdded) { + if ((node = get_node_info(notif->nodeid))) { + pthread_mutex_lock(&znodes_mutex); + node->values.push_back(value); + pthread_mutex_unlock(&znodes_mutex); + } + OpenZWave::Manager::Get()->SetChangeVerified(value, true); + } + + + /* + * Common value types. + */ + valobj->Set(String::NewFromUtf8(isolate, "type", String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Value::GetTypeNameFromEnum (value.GetType()))); + + valobj->Set(String::NewFromUtf8(isolate, "genre", String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Value::GetGenreNameFromEnum(value.GetGenre()))); + + valobj->Set(String::NewFromUtf8(isolate, "instance", String::kInternalizedString), + Integer::New(isolate,value.GetInstance())); + + valobj->Set(String::NewFromUtf8(isolate, "index", String::kInternalizedString), + Integer::New(isolate, value.GetIndex())); + + valobj->Set(String::NewFromUtf8(isolate, "label", String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Manager::Get()->GetValueLabel(value).c_str())); + + valobj->Set(String::NewFromUtf8(isolate, "units", String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Manager::Get()->GetValueUnits(value).c_str())); + + valobj->Set(String::NewFromUtf8(isolate, "read_only", String::kInternalizedString), + Boolean::New(isolate,OpenZWave::Manager::Get()->IsValueReadOnly(value))->ToBoolean()); + + valobj->Set(String::NewFromUtf8(isolate, "write_only", String::kInternalizedString), + Boolean::New(isolate,OpenZWave::Manager::Get()->IsValueWriteOnly(value))->ToBoolean()); + + // XXX: verify_changes= + // XXX: poll_intensity= + valobj->Set(String::NewFromUtf8(isolate, "min", String::kInternalizedString), + Integer::New(isolate,OpenZWave::Manager::Get()->GetValueMin(value))); + + valobj->Set(String::NewFromUtf8(isolate, "max", String::kInternalizedString), + Integer::New(isolate,OpenZWave::Manager::Get()->GetValueMax(value))); + + /* + * The value itself is type-specific. + */ + switch (value.GetType()) { + case OpenZWave::ValueID::ValueType_Bool: + { + bool val; + OpenZWave::Manager::Get()->GetValueAsBool(value, &val); + valobj->Set(String::NewFromUtf8(isolate, "value", String::kInternalizedString), Boolean::New(isolate,val)->ToBoolean()); + break; + } + case OpenZWave::ValueID::ValueType_Byte: + { + uint8_t val; + OpenZWave::Manager::Get()->GetValueAsByte(value, &val); + valobj->Set(String::NewFromUtf8(isolate, "value", String::kInternalizedString), Integer::New(isolate,val)); + break; + } + case OpenZWave::ValueID::ValueType_Decimal: + { + float val; + OpenZWave::Manager::Get()->GetValueAsFloat(value, &val); + valobj->Set(String::NewFromUtf8(isolate, "value", String::kInternalizedString), Integer::New(isolate,val)); + break; + } + case OpenZWave::ValueID::ValueType_Int: + { + int32_t val; + OpenZWave::Manager::Get()->GetValueAsInt(value, &val); + valobj->Set(String::NewFromUtf8(isolate, "value", String::kInternalizedString), Integer::New(isolate,val)); + break; + } + case OpenZWave::ValueID::ValueType_List: + { + Local items; + } + case OpenZWave::ValueID::ValueType_Short: + { + int16_t val; + OpenZWave::Manager::Get()->GetValueAsShort(value, &val); + valobj->Set(String::NewFromUtf8(isolate, "value", String::kInternalizedString), Integer::New(isolate,val)); + break; + } + case OpenZWave::ValueID::ValueType_String: + { + std::string val; + OpenZWave::Manager::Get()->GetValueAsString(value, &val); + valobj->Set(String::NewFromUtf8(isolate, "value", String::kInternalizedString), String::NewFromUtf8(isolate, val.c_str())); + break; + } + /* + * Buttons do not have a value. + */ + case OpenZWave::ValueID::ValueType_Button: + { + break; + } + default: + fprintf(stderr, "unsupported value type: 0x%x\n", value.GetType()); + break; + } + + args[0] = String::NewFromUtf8(isolate, evname); + args[1] = Integer::New(isolate,notif->nodeid); + args[2] = Integer::New(isolate,value.GetCommandClassId()); + args[3] = valobj; + MakeCallback(isolate, Local::New(isolate, context_obj), "emit", 4, args); + + break; + } + /* + * A value update was sent but nothing changed, likely due to + * the value just being polled. Ignore, as we handle actual + * changes above. + */ + case OpenZWave::Notification::Type_ValueRefreshed: + break; + case OpenZWave::Notification::Type_ValueRemoved: + { + OpenZWave::ValueID value = notif->values.front(); + std::list::iterator vit; + if ((node = get_node_info(notif->nodeid))) { + for (vit = node->values.begin(); vit != node->values.end(); ++vit) { + if ((*vit) == notif->values.front()) { + node->values.erase(vit); + break; + } + } + } + args[0] = String::NewFromUtf8(isolate, "value removed"); + args[1] = Integer::New(isolate,notif->nodeid); + args[2] = Integer::New(isolate,value.GetCommandClassId()); + args[3] = Integer::New(isolate,value.GetIndex()); + MakeCallback(isolate, Local::New(isolate, context_obj), "emit", 4, args); + break; + } + /* + * I believe this means that the node is now ready to accept + * commands, however for now we will wait until all queries are + * complete before notifying upstack, just in case. + */ + case OpenZWave::Notification::Type_EssentialNodeQueriesComplete: + break; + /* + * The node is now fully ready for operation. + */ + case OpenZWave::Notification::Type_NodeQueriesComplete: + { + Local info = Object::New(isolate); + info->Set(String::NewFromUtf8(isolate,"manufacturer",String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Manager::Get()->GetNodeManufacturerName(notif->homeid, notif->nodeid).c_str())); + info->Set(String::NewFromUtf8(isolate, "manufacturerid", String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Manager::Get()->GetNodeManufacturerId(notif->homeid, notif->nodeid).c_str())); + info->Set(String::NewFromUtf8(isolate, "product", String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Manager::Get()->GetNodeProductName(notif->homeid, notif->nodeid).c_str())); + info->Set(String::NewFromUtf8(isolate, "producttype", String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Manager::Get()->GetNodeProductType(notif->homeid, notif->nodeid).c_str())); + info->Set(String::NewFromUtf8(isolate, "productid", String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Manager::Get()->GetNodeProductId(notif->homeid, notif->nodeid).c_str())); + info->Set(String::NewFromUtf8(isolate, "type", String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Manager::Get()->GetNodeType(notif->homeid, notif->nodeid).c_str())); + info->Set(String::NewFromUtf8(isolate, "name", String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Manager::Get()->GetNodeName(notif->homeid, notif->nodeid).c_str())); + info->Set(String::NewFromUtf8(isolate, "loc", String::kInternalizedString), + String::NewFromUtf8(isolate, OpenZWave::Manager::Get()->GetNodeLocation(notif->homeid, notif->nodeid).c_str())); + args[0] = String::NewFromUtf8(isolate, "node ready"); + args[1] = Integer::New(isolate, notif->nodeid); + args[2] = info; + MakeCallback(isolate, Local::New(isolate, context_obj), "emit", 3, args); + break; + } + /* + * The network scan has been completed. Currently we do not + * care about dead nodes - is there anything we can do anyway? + */ + case OpenZWave::Notification::Type_AwakeNodesQueried: + case OpenZWave::Notification::Type_AllNodesQueried: + case OpenZWave::Notification::Type_AllNodesQueriedSomeDead: + args[0] = String::NewFromUtf8(isolate, "scan complete"); + MakeCallback(isolate, Local::New(isolate, context_obj), "emit", 1, args); + break; + /* + * A general notification. + */ + case OpenZWave::Notification::Type_Notification: + args[0] = String::NewFromUtf8(isolate, "notification"); + args[1] = Integer::New(isolate,notif->nodeid); + args[2] = Integer::New(isolate,notif->notification); + MakeCallback(isolate, Local::New(isolate, context_obj), "emit", 3, args); + break; + /* + * Send unhandled events to stderr so we can monitor them if + * necessary. + */ + default: + fprintf(stderr, "Unhandled notification: %d\n", notif->type); + break; + } + + zqueue.pop(); + } + + pthread_mutex_unlock(&zqueue_mutex); } -Handle OZW::New(const Arguments& args) +void OZW::New(const FunctionCallbackInfo& args) { - HandleScope scope; - - assert(args.IsConstructCall()); - OZW* self = new OZW(); - self->Wrap(args.This()); - - Local opts = args[0]->ToObject(); - std::string confpath = (*String::Utf8Value(opts->Get(String::New("modpath")->ToString()))); - confpath += "/../deps/open-zwave/config"; - - /* - * Options are global for all drivers and can only be set once. - */ - OpenZWave::Options::Create(confpath.c_str(), "", ""); - OpenZWave::Options::Get()->AddOptionBool("ConsoleOutput", opts->Get(String::New("consoleoutput"))->BooleanValue()); - OpenZWave::Options::Get()->AddOptionBool("Logging", opts->Get(String::New("logging"))->BooleanValue()); - OpenZWave::Options::Get()->AddOptionBool("SaveConfiguration", opts->Get(String::New("saveconfig"))->BooleanValue()); - OpenZWave::Options::Get()->AddOptionInt("DriverMaxAttempts", opts->Get(String::New("driverattempts"))->IntegerValue()); - OpenZWave::Options::Get()->AddOptionInt("PollInterval", opts->Get(String::New("pollinterval"))->IntegerValue()); - OpenZWave::Options::Get()->AddOptionBool("IntervalBetweenPolls", true); - OpenZWave::Options::Get()->AddOptionBool("SuppressValueRefresh", opts->Get(String::New("suppressrefresh"))->BooleanValue()); - OpenZWave::Options::Get()->Lock(); - - return scope.Close(args.This()); + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); + + assert(args.IsConstructCall()); + OZW* self = new OZW(); + self->Wrap(args.This()); + + Local opts = args[0]->ToObject(); + String::Utf8Value modPath(opts->Get(String::NewFromUtf8(isolate, "modpath"))->ToString()); + std::string confpath = std::string(*modPath); + confpath += "/../deps/open-zwave/config"; + + /* + * Options are global for all drivers and can only be set once. + */ + OpenZWave::Options::Create(confpath.c_str(), "", ""); + OpenZWave::Options::Get()->AddOptionBool("ConsoleOutput", opts->Get(String::NewFromUtf8(isolate, "consoleoutput"))->BooleanValue()); + OpenZWave::Options::Get()->AddOptionBool("Logging", opts->Get(String::NewFromUtf8(isolate, "logging"))->BooleanValue()); + OpenZWave::Options::Get()->AddOptionBool("SaveConfiguration", opts->Get(String::NewFromUtf8(isolate, "saveconfig"))->BooleanValue()); + OpenZWave::Options::Get()->AddOptionInt("DriverMaxAttempts", opts->Get(String::NewFromUtf8(isolate, "driverattempts"))->IntegerValue()); + OpenZWave::Options::Get()->AddOptionInt("PollInterval", opts->Get(String::NewFromUtf8(isolate, "pollinterval"))->IntegerValue()); + OpenZWave::Options::Get()->AddOptionBool("IntervalBetweenPolls", true); + OpenZWave::Options::Get()->AddOptionBool("SuppressValueRefresh", opts->Get(String::NewFromUtf8(isolate, "suppressrefresh"))->BooleanValue()); + OpenZWave::Options::Get()->Lock(); + + args.GetReturnValue().Set(args.This()); } -Handle OZW::Connect(const Arguments& args) +void OZW::Connect(const FunctionCallbackInfo& args) { - HandleScope scope; + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); - std::string path = (*String::Utf8Value(args[0]->ToString())); + std::string path = (*String::Utf8Value(args[0]->ToString())); - uv_async_init(uv_default_loop(), &async, async_cb_handler); + uv_async_init(uv_default_loop(), &async, async_cb_handler); - context_obj = Persistent::New(args.This()); - OpenZWave::Manager::Create(); - OpenZWave::Manager::Get()->AddWatcher(cb, NULL); - OpenZWave::Manager::Get()->AddDriver(path); + context_obj.Reset(isolate, args.This()); - Handle argv[1] = { String::New("connected") }; - MakeCallback(context_obj, "emit", 1, argv); + OpenZWave::Manager::Create(); + OpenZWave::Manager::Get()->AddWatcher(cb, NULL); + OpenZWave::Manager::Get()->AddDriver(path); + + Handle argv[1] = { String::NewFromUtf8(isolate, "connected") }; + node::MakeCallback(isolate, Local::New(isolate, context_obj), "emit", 1, argv); - return Undefined(); } -Handle OZW::Disconnect(const Arguments& args) +void OZW::Disconnect(const FunctionCallbackInfo& args) { - HandleScope scope; - - std::string path = (*String::Utf8Value(args[0]->ToString())); + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); - OpenZWave::Manager::Get()->RemoveDriver(path); - OpenZWave::Manager::Get()->RemoveWatcher(cb, NULL); - OpenZWave::Manager::Destroy(); - OpenZWave::Options::Destroy(); + std::string path = (*String::Utf8Value(args[0]->ToString())); - return scope.Close(Undefined()); + OpenZWave::Manager::Get()->RemoveDriver(path); + OpenZWave::Manager::Get()->RemoveWatcher(cb, NULL); + OpenZWave::Manager::Destroy(); + OpenZWave::Options::Destroy(); } /* * Generic value set. */ -Handle OZW::SetValue(const Arguments& args) +void OZW::SetValue(const FunctionCallbackInfo& args) { - HandleScope scope; - - uint8_t nodeid = args[0]->ToNumber()->Value(); - uint8_t comclass = args[1]->ToNumber()->Value(); - uint8_t index = args[2]->ToNumber()->Value(); - - NodeInfo *node; - std::list::iterator vit; - - if ((node = get_node_info(nodeid))) { - for (vit = node->values.begin(); vit != node->values.end(); ++vit) { - if (((*vit).GetCommandClassId() == comclass) && - ((*vit).GetIndex() == index)) { - - switch ((*vit).GetType()) { - case OpenZWave::ValueID::ValueType_Bool: - { - bool val = args[3]->ToBoolean()->Value(); - OpenZWave::Manager::Get()->SetValue(*vit, val); - break; - } - case OpenZWave::ValueID::ValueType_Byte: - { - uint8_t val = args[3]->ToInteger()->Value(); - OpenZWave::Manager::Get()->SetValue(*vit, val); - break; - } - case OpenZWave::ValueID::ValueType_Decimal: - { - float val = args[3]->ToNumber()->NumberValue(); - OpenZWave::Manager::Get()->SetValue(*vit, val); - break; - } - case OpenZWave::ValueID::ValueType_Int: - { - int32_t val = args[3]->ToInteger()->Value(); - OpenZWave::Manager::Get()->SetValue(*vit, val); - break; - } - case OpenZWave::ValueID::ValueType_Short: - { - int16_t val = args[3]->ToInteger()->Value(); - OpenZWave::Manager::Get()->SetValue(*vit, val); - break; - } - case OpenZWave::ValueID::ValueType_String: - { - std::string val = (*String::Utf8Value(args[3]->ToString())); - OpenZWave::Manager::Get()->SetValue(*vit, val); - break; - } - } - } - } - } - - return scope.Close(Undefined()); + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); + + uint8_t nodeid = args[0]->ToNumber()->Value(); + uint8_t comclass = args[1]->ToNumber()->Value(); + uint8_t index = args[2]->ToNumber()->Value(); + + NodeInfo *node; + std::list::iterator vit; + + if ((node = get_node_info(nodeid))) { + for (vit = node->values.begin(); vit != node->values.end(); ++vit) { + if (((*vit).GetCommandClassId() == comclass) && + ((*vit).GetIndex() == index)) { + + switch ((*vit).GetType()) { + case OpenZWave::ValueID::ValueType_Bool: + { + bool val = args[3]->ToBoolean()->Value(); + OpenZWave::Manager::Get()->SetValue(*vit, val); + break; + } + case OpenZWave::ValueID::ValueType_Byte: + { + uint8_t val = args[3]->ToInteger()->Value(); + OpenZWave::Manager::Get()->SetValue(*vit, val); + break; + } + case OpenZWave::ValueID::ValueType_Decimal: + { + float val = args[3]->ToNumber()->NumberValue(); + OpenZWave::Manager::Get()->SetValue(*vit, val); + break; + } + case OpenZWave::ValueID::ValueType_Int: + { + int32_t val = args[3]->ToInteger()->Value(); + OpenZWave::Manager::Get()->SetValue(*vit, val); + break; + } + case OpenZWave::ValueID::ValueType_Short: + { + int16_t val = args[3]->ToInteger()->Value(); + OpenZWave::Manager::Get()->SetValue(*vit, val); + break; + } + case OpenZWave::ValueID::ValueType_String: + { + std::string val = (*String::Utf8Value(args[3]->ToString())); + OpenZWave::Manager::Get()->SetValue(*vit, val); + break; + } + } + } + } + } + } /* * Set a COMMAND_CLASS_SWITCH_MULTILEVEL device to a specific value. */ -Handle OZW::SetLevel(const Arguments& args) +void OZW::SetLevel(const FunctionCallbackInfo& args) { - HandleScope scope; + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); - uint8_t nodeid = args[0]->ToNumber()->Value(); - uint8_t value = args[1]->ToNumber()->Value(); + uint8_t nodeid = args[0]->ToNumber()->Value(); + uint8_t value = args[1]->ToNumber()->Value(); - NodeInfo *node; - std::list::iterator vit; + NodeInfo *node; + std::list::iterator vit; - if ((node = get_node_info(nodeid))) { - for (vit = node->values.begin(); vit != node->values.end(); ++vit) { - if ((*vit).GetCommandClassId() == 0x26 && (*vit).GetIndex() == 0) { - OpenZWave::Manager::Get()->SetValue(*vit, value); - break; - } - } - } + if ((node = get_node_info(nodeid))) { + for (vit = node->values.begin(); vit != node->values.end(); ++vit) { + if ((*vit).GetCommandClassId() == 0x26 && (*vit).GetIndex() == 0) { + OpenZWave::Manager::Get()->SetValue(*vit, value); + break; + } + } + } - return scope.Close(Undefined()); } /* * Write a new location string to the device, if supported. */ -Handle OZW::SetLocation(const Arguments& args) +void OZW::SetLocation(const FunctionCallbackInfo& args) { - HandleScope scope; - - uint8_t nodeid = args[0]->ToNumber()->Value(); - std::string location = (*String::Utf8Value(args[1]->ToString())); + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); - OpenZWave::Manager::Get()->SetNodeLocation(homeid, nodeid, location); + uint8_t nodeid = args[0]->ToNumber()->Value(); + std::string location = (*String::Utf8Value(args[1]->ToString())); - return scope.Close(Undefined()); + OpenZWave::Manager::Get()->SetNodeLocation(homeid, nodeid, location); } /* * Write a new name string to the device, if supported. */ -Handle OZW::SetName(const Arguments& args) +void OZW::SetName(const FunctionCallbackInfo& args) { - HandleScope scope; - - uint8_t nodeid = args[0]->ToNumber()->Value(); - std::string name = (*String::Utf8Value(args[1]->ToString())); + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); - OpenZWave::Manager::Get()->SetNodeName(homeid, nodeid, name); + uint8_t nodeid = args[0]->ToNumber()->Value(); + String::Utf8Value argsName(args[1]->ToString()); + std::string name = (*argsName); - return scope.Close(Undefined()); + OpenZWave::Manager::Get()->SetNodeName(homeid, nodeid, name); } /* @@ -603,124 +618,126 @@ Handle OZW::SetName(const Arguments& args) */ void set_switch(uint8_t nodeid, bool state) { - NodeInfo *node; - std::list::iterator vit; - - if ((node = get_node_info(nodeid))) { - for (vit = node->values.begin(); vit != node->values.end(); ++vit) { - if ((*vit).GetCommandClassId() == 0x25) { - OpenZWave::Manager::Get()->SetValue(*vit, state); - break; - } - } - } + NodeInfo *node; + std::list::iterator vit; + + if ((node = get_node_info(nodeid))) { + for (vit = node->values.begin(); vit != node->values.end(); ++vit) { + if ((*vit).GetCommandClassId() == 0x25) { + OpenZWave::Manager::Get()->SetValue(*vit, state); + break; + } + } + } } -Handle OZW::SwitchOn(const Arguments& args) +void OZW::SwitchOn(const FunctionCallbackInfo& args) { - HandleScope scope; + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); - uint8_t nodeid = args[0]->ToNumber()->Value(); - set_switch(nodeid, true); - - return scope.Close(Undefined()); + uint8_t nodeid = args[0]->ToNumber()->Value(); + set_switch(nodeid, true); } -Handle OZW::SwitchOff(const Arguments& args) + + +void OZW::SwitchOff(const FunctionCallbackInfo& args) { - HandleScope scope; + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); - uint8_t nodeid = args[0]->ToNumber()->Value(); - set_switch(nodeid, false); + uint8_t nodeid = args[0]->ToNumber()->Value(); + set_switch(nodeid, false); - return scope.Close(Undefined()); } /* * Enable/Disable polling on a COMMAND_CLASS basis. */ -Handle OZW::EnablePoll(const Arguments& args) +void OZW::EnablePoll(const FunctionCallbackInfo& args) { - HandleScope scope; - - uint8_t nodeid = args[0]->ToNumber()->Value(); - uint8_t comclass = args[1]->ToNumber()->Value(); - NodeInfo *node; - std::list::iterator vit; - - if ((node = get_node_info(nodeid))) { - for (vit = node->values.begin(); vit != node->values.end(); ++vit) { - if ((*vit).GetCommandClassId() == comclass) { - OpenZWave::Manager::Get()->EnablePoll((*vit), 1); - break; - } - } - } - - return scope.Close(Undefined()); + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); + + uint8_t nodeid = args[0]->ToNumber()->Value(); + uint8_t comclass = args[1]->ToNumber()->Value(); + NodeInfo *node; + std::list::iterator vit; + + if ((node = get_node_info(nodeid))) { + for (vit = node->values.begin(); vit != node->values.end(); ++vit) { + if ((*vit).GetCommandClassId() == comclass) { + OpenZWave::Manager::Get()->EnablePoll((*vit), 1); + break; + } + } + } } -Handle OZW::DisablePoll(const Arguments& args) + +void OZW::DisablePoll(const FunctionCallbackInfo& args) { - HandleScope scope; - - uint8_t nodeid = args[0]->ToNumber()->Value(); - uint8_t comclass = args[1]->ToNumber()->Value(); - NodeInfo *node; - std::list::iterator vit; - - if ((node = get_node_info(nodeid))) { - for (vit = node->values.begin(); vit != node->values.end(); ++vit) { - if ((*vit).GetCommandClassId() == comclass) { - OpenZWave::Manager::Get()->DisablePoll((*vit)); - break; - } - } - } - - return scope.Close(Undefined()); + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); + + uint8_t nodeid = args[0]->ToNumber()->Value(); + uint8_t comclass = args[1]->ToNumber()->Value(); + NodeInfo *node; + std::list::iterator vit; + + if ((node = get_node_info(nodeid))) { + for (vit = node->values.begin(); vit != node->values.end(); ++vit) { + if ((*vit).GetCommandClassId() == comclass) { + OpenZWave::Manager::Get()->DisablePoll((*vit)); + break; + } + } + } + } /* * Reset the ZWave controller chip. A hard reset is destructive and wipes * out all known configuration, a soft reset just restarts the chip. */ -Handle OZW::HardReset(const Arguments& args) +void OZW::HardReset(const FunctionCallbackInfo& args) { - HandleScope scope; + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); - OpenZWave::Manager::Get()->ResetController(homeid); + OpenZWave::Manager::Get()->ResetController(homeid); - return scope.Close(Undefined()); + args.GetReturnValue().SetUndefined(); } -Handle OZW::SoftReset(const Arguments& args) +void OZW::SoftReset(const FunctionCallbackInfo& args) { - HandleScope scope; - - OpenZWave::Manager::Get()->SoftReset(homeid); - - return scope.Close(Undefined()); + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); + OpenZWave::Manager::Get()->SoftReset(homeid); + args.GetReturnValue().SetUndefined(); } extern "C" void init(Handle target) { - HandleScope scope; - - Local t = FunctionTemplate::New(OZW::New); - t->InstanceTemplate()->SetInternalFieldCount(1); - t->SetClassName(String::New("OZW")); - - NODE_SET_PROTOTYPE_METHOD(t, "connect", OZW::Connect); - NODE_SET_PROTOTYPE_METHOD(t, "disconnect", OZW::Disconnect); - NODE_SET_PROTOTYPE_METHOD(t, "setValue", OZW::SetValue); - NODE_SET_PROTOTYPE_METHOD(t, "setLevel", OZW::SetLevel); - NODE_SET_PROTOTYPE_METHOD(t, "setLocation", OZW::SetLocation); - NODE_SET_PROTOTYPE_METHOD(t, "setName", OZW::SetName); - NODE_SET_PROTOTYPE_METHOD(t, "switchOn", OZW::SwitchOn); - NODE_SET_PROTOTYPE_METHOD(t, "switchOff", OZW::SwitchOff); - NODE_SET_PROTOTYPE_METHOD(t, "enablePoll", OZW::EnablePoll); - NODE_SET_PROTOTYPE_METHOD(t, "disablePoll", OZW::EnablePoll); - NODE_SET_PROTOTYPE_METHOD(t, "hardReset", OZW::HardReset); - NODE_SET_PROTOTYPE_METHOD(t, "softReset", OZW::SoftReset); - - target->Set(String::NewSymbol("Emitter"), t->GetFunction()); + Isolate* isolate = Isolate::GetCurrent(); + HandleScope scope(isolate); + + Local t = FunctionTemplate::New(isolate,OZW::New); + t->InstanceTemplate()->SetInternalFieldCount(1); + t->SetClassName(String::NewFromUtf8(isolate,"OZW")); + + NODE_SET_PROTOTYPE_METHOD(t, "connect", OZW::Connect); + NODE_SET_PROTOTYPE_METHOD(t, "disconnect", OZW::Disconnect); + NODE_SET_PROTOTYPE_METHOD(t, "setValue", OZW::SetValue); + NODE_SET_PROTOTYPE_METHOD(t, "setLevel", OZW::SetLevel); + NODE_SET_PROTOTYPE_METHOD(t, "setLocation", OZW::SetLocation); + NODE_SET_PROTOTYPE_METHOD(t, "setName", OZW::SetName); + NODE_SET_PROTOTYPE_METHOD(t, "switchOn", OZW::SwitchOn); + NODE_SET_PROTOTYPE_METHOD(t, "switchOff", OZW::SwitchOff); + NODE_SET_PROTOTYPE_METHOD(t, "enablePoll", OZW::EnablePoll); + NODE_SET_PROTOTYPE_METHOD(t, "disablePoll", OZW::EnablePoll); + NODE_SET_PROTOTYPE_METHOD(t, "hardReset", OZW::HardReset); + NODE_SET_PROTOTYPE_METHOD(t, "softReset", OZW::SoftReset); + + target->Set(String::NewFromUtf8(isolate,"Emitter"), t->GetFunction()); } }