Fix new schema to match the new server definitions A new server version now validates the state definitions in traits as well as commands and some of our sample traits were not defined properly. Also, the server now requires the 'base' trait to be complete (and have base.reboot and base.identify commands defined). Change-Id: Icc576918895eba642498aa9b8bb1771825562f06 Reviewed-on: https://weave-review.googlesource.com/1971 Reviewed-by: Vitaly Buka <vitalybuka@google.com>
diff --git a/examples/daemon/ledflasher/ledflasher.cc b/examples/daemon/ledflasher/ledflasher.cc index e63deac..d26728f 100644 --- a/examples/daemon/ledflasher/ledflasher.cc +++ b/examples/daemon/ledflasher/ledflasher.cc
@@ -18,21 +18,21 @@ const char kTraits[] = R"({ "_ledflasher": { "commands": { - "_set": { + "set": { "minimalRole": "user", "parameters": { - "_led": { + "led": { "type": "integer", "minimum": 1, "maximum": 3 }, - "_on": { "type": "boolean" } + "on": { "type": "boolean" } } }, - "_toggle": { + "toggle": { "minimalRole": "user", "parameters": { - "_led": { + "led": { "type": "integer", "minimum": 1, "maximum": 3 @@ -41,7 +41,7 @@ } }, "state": { - "_leds": { + "leds": { "type": "array", "items": { "type": "boolean" } } @@ -66,11 +66,11 @@ UpdateLedState(); device->AddCommandHandler( - kComponent, "_ledflasher._toggle", + kComponent, "_ledflasher.toggle", base::Bind(&LedFlasherHandler::OnFlasherToggleCommand, weak_ptr_factory_.GetWeakPtr())); device->AddCommandHandler( - kComponent, "_ledflasher._set", + kComponent, "_ledflasher.set", base::Bind(&LedFlasherHandler::OnFlasherSetCommand, weak_ptr_factory_.GetWeakPtr())); } @@ -134,7 +134,7 @@ for (uint32_t i = 0; i < led_status_.size(); i++) list.AppendBoolean(led_status_[i] ? true : false); - device_->SetStateProperty(kComponent, "_ledflasher._leds", list, nullptr); + device_->SetStateProperty(kComponent, "_ledflasher.leds", list, nullptr); } weave::Device* device_{nullptr};
diff --git a/examples/daemon/light/light.cc b/examples/daemon/light/light.cc index 035ef4e..298fcaf 100644 --- a/examples/daemon/light/light.cc +++ b/examples/daemon/light/light.cc
@@ -27,7 +27,8 @@ "state": { "state": { "type": "string", - "enum": [ "on", "standby" ] + "enum": [ "on", "standby" ], + "isRequired": true } } }, @@ -44,7 +45,14 @@ } } }, - "state": { "brightness": { "type": "integer" } } + "state": { + "brightness": { + "type": "integer", + "isRequired": true, + "minimum": 0, + "maximum": 100 + } + } }, "colorXY": { "commands": { @@ -71,11 +79,15 @@ }, "additionalProperties": false } - } + }, + "errors": ["colorOutOfRange"] } }, "state": { "colorSetting": { + "type": "object", + "isRequired": true, + "required": [ "colorX", "colorY" ], "properties": { "colorX": { "type": "number", @@ -90,6 +102,9 @@ } }, "colorCapRed": { + "type": "object", + "isRequired": true, + "required": [ "colorX", "colorY" ], "properties": { "colorX": { "type": "number", @@ -104,6 +119,9 @@ } }, "colorCapGreen": { + "type": "object", + "isRequired": true, + "required": [ "colorX", "colorY" ], "properties": { "colorX": { "type": "number", @@ -118,6 +136,9 @@ } }, "colorCapBlue": { + "type": "object", + "isRequired": true, + "required": [ "colorX", "colorY" ], "properties": { "colorX": { "type": "number",
diff --git a/examples/daemon/lock/lock.cc b/examples/daemon/lock/lock.cc index 1137b92..0785c14 100644 --- a/examples/daemon/lock/lock.cc +++ b/examples/daemon/lock/lock.cc
@@ -37,15 +37,20 @@ "type": "string", "enum": [ "locked", "unlocked" ] } - } + }, + "errors": ["batteryTooLow", "jammed", "lockingNotSupported"] } }, "state": { "lockedState": { "type": "string", - "enum": [ "locked", "unlocked", "partiallyLocked" ] + "enum": [ "locked", "unlocked", "partiallyLocked" ], + "isRequired": true }, - "isLockingSupported": { "type": "boolean" } + "isLockingSupported": { + "type": "boolean", + "isRequired": true + } } } })";
diff --git a/examples/daemon/oven/oven.cc b/examples/daemon/oven/oven.cc index 151561d..ff1c60b 100644 --- a/examples/daemon/oven/oven.cc +++ b/examples/daemon/oven/oven.cc
@@ -30,7 +30,50 @@ "tempSetting": { "type": "number" } - } + }, + "errors": ["tempOutOfRange", "unsupportedUnits"] + } + }, + "state": { + "supportedUnits": { + "type": "array", + "items": { + "type": "string", + "enum": [ "celsius", "fahrenheit", "kelvin" ] + }, + "minItems": 1, + "uniqueItems": true, + "isRequired": true + }, + "units": { + "type": "string", + "enum": [ "celsius", "fahrenheit", "kelvin" ], + "isRequired": true + }, + "tempSetting": { + "type": "number", + "isRequired": true + }, + "maxTempSetting": { + "type": "number", + "isRequired": true + }, + "minTempSetting": { + "type": "number", + "isRequired": true + } + } + }, + "temperatureSensor": { + "commands": { + "setConfig": { + "minimalRole": "user", + "parameters": { + "units": { + "type": "string" + } + }, + "errors": ["unsupportedUnits"] } }, "state": { @@ -43,40 +86,19 @@ "fahrenheit", "kelvin" ] - } + }, + "minItems": 1, + "uniqueItems": true, + "isRequired": true }, "units": { - "type": "string" - }, - "tempSetting": { - "type": "number" - }, - "maxTempSetting": { - "type": "number" - }, - "minTempSetting": { - "type": "number" - } - } - }, - "temperatureSensor": { - "state": { - "supportedUnits": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "celsius", - "fahrenheit", - "kelvin" - ] - } - }, - "units": { - "type": "string" + "type": "string", + "enum": [ "celsius", "fahrenheit", "kelvin" ], + "isRequired": true }, "value": { - "type": "number" + "type": "number", + "isRequired": true } } }, @@ -95,7 +117,10 @@ }, "state": { "brightness": { - "type": "number" + "type": "integer", + "isRequired": true, + "minimum": 0, + "maximum": 100 } } }
diff --git a/examples/daemon/sample/sample.cc b/examples/daemon/sample/sample.cc index 2ab4b27..1d036d5 100644 --- a/examples/daemon/sample/sample.cc +++ b/examples/daemon/sample/sample.cc
@@ -15,19 +15,20 @@ const char kTraits[] = R"({ "_sample": { "commands": { - "_hello": { + "hello": { "minimalRole": "user", "parameters": { - "_name": { "type": "string" } + "name": { "type": "string" } } }, - "_ping": { - "minimalRole": "user" + "ping": { + "minimalRole": "user", + "parameters": {} }, - "_countdown": { + "countdown": { "minimalRole": "user", "parameters": { - "_seconds": { + "seconds": { "type": "integer", "minimum": 1, "maximum": 25 @@ -36,7 +37,7 @@ } }, "state": { - "_ping_count": { "type": "integer" } + "pingCount": { "type": "integer" } } } })"; @@ -60,15 +61,15 @@ device->AddTraitDefinitionsFromJson(kTraits); CHECK(device->AddComponent(kComponent, {"_sample"}, nullptr)); CHECK(device->SetStatePropertiesFromJson( - kComponent, R"({"_sample": {"_ping_count": 0}})", nullptr)); + kComponent, R"({"_sample": {"pingCount": 0}})", nullptr)); - device->AddCommandHandler(kComponent, "_sample._hello", + device->AddCommandHandler(kComponent, "_sample.hello", base::Bind(&SampleHandler::OnHelloCommand, weak_ptr_factory_.GetWeakPtr())); - device->AddCommandHandler(kComponent, "_sample._ping", + device->AddCommandHandler(kComponent, "_sample.ping", base::Bind(&SampleHandler::OnPingCommand, weak_ptr_factory_.GetWeakPtr())); - device->AddCommandHandler(kComponent, "_sample._countdown", + device->AddCommandHandler(kComponent, "_sample.countdown", base::Bind(&SampleHandler::OnCountdownCommand, weak_ptr_factory_.GetWeakPtr())); } @@ -82,7 +83,7 @@ const auto& params = cmd->GetParameters(); std::string name; - if (!params.GetString("_name", &name)) { + if (!params.GetString("name", &name)) { weave::ErrorPtr error; weave::Error::AddTo(&error, FROM_HERE, "example", "invalid_parameter_value", "Name is missing"); @@ -91,7 +92,7 @@ } base::DictionaryValue result; - result.SetString("_reply", "Hello " + name); + result.SetString("reply", "Hello " + name); cmd->Complete(result, nullptr); LOG(INFO) << cmd->GetName() << " command finished: " << result; } @@ -102,7 +103,7 @@ return; LOG(INFO) << "received command: " << cmd->GetName(); - device_->SetStateProperty(kComponent, "_sample._ping_count", + device_->SetStateProperty(kComponent, "_sample.pingCount", base::FundamentalValue{++ping_count_}, nullptr); LOG(INFO) << "New component state: " << device_->GetComponents(); @@ -120,7 +121,7 @@ const auto& params = cmd->GetParameters(); int seconds; - if (!params.GetInteger("_seconds", &seconds)) + if (!params.GetInteger("seconds", &seconds)) seconds = 10; LOG(INFO) << "starting countdown"; @@ -133,13 +134,9 @@ return; if (seconds > 0) { - const auto& params = cmd->GetParameters(); - std::string todo; - params.GetString("_todo", &todo); LOG(INFO) << "countdown tick: " << seconds << " seconds left"; - base::DictionaryValue progress; - progress.SetInteger("_seconds_left", seconds); + progress.SetInteger("seconds_left", seconds); cmd->SetProgress(progress, nullptr); task_runner_->PostDelayedTask( FROM_HERE,
diff --git a/examples/daemon/speaker/speaker.cc b/examples/daemon/speaker/speaker.cc index 8b3e41b..35eee2f 100644 --- a/examples/daemon/speaker/speaker.cc +++ b/examples/daemon/speaker/speaker.cc
@@ -25,8 +25,11 @@ } }, "state": { - "type": "string", - "enum": [ "on", "standby" ] + "state": { + "type": "string", + "enum": [ "on", "standby" ], + "isRequired": true + } } }, "volume": { @@ -44,8 +47,16 @@ } }, "state": { - "isMuted": { "type": "boolean" }, - "volume": { "type": "integer" } + "isMuted": { + "type": "boolean", + "isRequired": true + }, + "volume": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "isRequired": true + } } } })";
diff --git a/src/base_api_handler.cc b/src/base_api_handler.cc index 9c64463..5562b6c 100644 --- a/src/base_api_handler.cc +++ b/src/base_api_handler.cc
@@ -13,7 +13,7 @@ namespace weave { namespace { -const char kBaseComponent[] = "weave"; +const char kBaseComponent[] = "base"; const char kBaseTrait[] = "base"; const char kBaseStateFirmwareVersion[] = "base.firmwareVersion"; const char kBaseStateAnonymousAccessRole[] = "base.localAnonymousAccessMaxRole"; @@ -55,13 +55,45 @@ "type": "string" } } + }, + "reboot": { + "minimalRole": "user", + "parameters": {}, + "errors": ["notEnoughBattery"] + }, + "identify": { + "minimalRole": "user", + "parameters": {} } }, "state": { - "firmwareVersion": "string", - "localDiscoveryEnabled": "boolean", - "localAnonymousAccessMaxRole": [ "none", "viewer", "user" ], - "localPairingEnabled": "boolean" + "firmwareVersion": { + "type": "string", + "isRequired": true + }, + "localDiscoveryEnabled": { + "type": "boolean", + "isRequired": true + }, + "localAnonymousAccessMaxRole": { + "type": "string", + "enum": [ "none", "viewer", "user" ], + "isRequired": true + }, + "localPairingEnabled": { + "type": "boolean", + "isRequired": true + }, + "connectionStatus": { + "type": "string" + }, + "network": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { "type": "string" } + } + } } } })");
diff --git a/src/base_api_handler_unittest.cc b/src/base_api_handler_unittest.cc index e0ebf88..6f8460b 100644 --- a/src/base_api_handler_unittest.cc +++ b/src/base_api_handler_unittest.cc
@@ -133,14 +133,46 @@ "type": "string" } } + }, + "reboot": { + "minimalRole": "user", + "parameters": {}, + "errors": ["notEnoughBattery"] + }, + "identify": { + "minimalRole": "user", + "parameters": {} } }, - "state": { - "firmwareVersion": "string", - "localAnonymousAccessMaxRole": [ "none", "viewer", "user" ], - "localDiscoveryEnabled": "boolean", - "localPairingEnabled": "boolean" - } + "state": { + "firmwareVersion": { + "type": "string", + "isRequired": true + }, + "localDiscoveryEnabled": { + "type": "boolean", + "isRequired": true + }, + "localAnonymousAccessMaxRole": { + "type": "string", + "enum": [ "none", "viewer", "user" ], + "isRequired": true + }, + "localPairingEnabled": { + "type": "boolean", + "isRequired": true + }, + "connectionStatus": { + "type": "string" + }, + "network": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { "type": "string" } + } + } + } })"; EXPECT_JSON_EQ(expected, *trait); } @@ -150,7 +182,7 @@ AddCommand(R"({ 'name' : 'base.updateBaseConfiguration', - 'component': 'weave', + 'component': 'base', 'parameters': { 'localDiscoveryEnabled': false, 'localAnonymousAccessMaxRole': 'none', @@ -171,7 +203,7 @@ AddCommand(R"({ 'name' : 'base.updateBaseConfiguration', - 'component': 'weave', + 'component': 'base', 'parameters': { 'localDiscoveryEnabled': true, 'localAnonymousAccessMaxRole': 'user', @@ -205,7 +237,7 @@ TEST_F(BaseApiHandlerTest, UpdateDeviceInfo) { AddCommand(R"({ 'name' : 'base.updateDeviceInfo', - 'component': 'weave', + 'component': 'base', 'parameters': { 'name': 'testName', 'description': 'testDescription', @@ -220,7 +252,7 @@ AddCommand(R"({ 'name' : 'base.updateDeviceInfo', - 'component': 'weave', + 'component': 'base', 'parameters': { 'location': 'newLocation' }
diff --git a/src/device_registration_info.cc b/src/device_registration_info.cc index 47fa40c..e70b8ba 100644 --- a/src/device_registration_info.cc +++ b/src/device_registration_info.cc
@@ -512,9 +512,6 @@ channel->SetString("supportedType", "pull"); } resource->Set("channel", channel.release()); - resource->Set("commandDefs", - component_manager_->GetLegacyCommandDefinitions().DeepCopy()); - resource->Set("state", component_manager_->GetLegacyState().DeepCopy()); resource->Set("traits", component_manager_->GetTraits().DeepCopy()); resource->Set("components", component_manager_->GetComponents().DeepCopy());
diff --git a/src/device_registration_info_unittest.cc b/src/device_registration_info_unittest.cc index 8be0c97..327c440 100644 --- a/src/device_registration_info_unittest.cc +++ b/src/device_registration_info_unittest.cc
@@ -430,73 +430,41 @@ EXPECT_TRUE(json->GetString("deviceDraft.name", &value)); EXPECT_EQ("Coffee Pot", value); base::DictionaryValue* dict = nullptr; - EXPECT_TRUE(json->GetDictionary("deviceDraft.commandDefs", &dict)); - auto expectedCommandDefs = R"({ - 'base': { - 'reboot': { - 'parameters': { - 'delay': { - 'minimum': 10, - 'type': 'integer' - } - }, - 'minimalRole': 'user' - } - }, - 'robot': { - '_jump': { - 'parameters': { - '_height': { - 'type': 'integer' - } - }, - 'minimalRole': 'user' - } - } - })"; - EXPECT_JSON_EQ(expectedCommandDefs, *dict); - - EXPECT_TRUE(json->GetDictionary("deviceDraft.state", &dict)); - auto expectedState = R"({ - 'base': { - 'firmwareVersion': '1.0' - } - })"; - EXPECT_JSON_EQ(expectedState, *dict); - + EXPECT_FALSE(json->GetDictionary("deviceDraft.commandDefs", &dict)); + EXPECT_FALSE(json->GetDictionary("deviceDraft.state", &dict)); EXPECT_TRUE(json->GetDictionary("deviceDraft.traits", &dict)); auto expectedTraits = R"({ - 'base': { - 'commands': { - 'reboot': { - 'parameters': {'delay': {'minimum': 10, 'type': 'integer'}}, - 'minimalRole': 'user' + 'base': { + 'commands': { + 'reboot': { + 'parameters': {'delay': {'minimum': 10, 'type': 'integer'}}, + 'minimalRole': 'user' + } + }, + 'state': { + 'firmwareVersion': {'type': 'string'} } }, - 'state': { - 'firmwareVersion': {'type': 'string'} - } - }, - 'robot': { - 'commands': { - '_jump': { - 'parameters': {'_height': {'type': 'integer'}}, - 'minimalRole': 'user' + 'robot': { + 'commands': { + '_jump': { + 'parameters': {'_height': {'type': 'integer'}}, + 'minimalRole': 'user' + } } } - } - })"; + })"; EXPECT_JSON_EQ(expectedTraits, *dict); EXPECT_TRUE(json->GetDictionary("deviceDraft.components", &dict)); auto expectedComponents = R"({ - 'comp': { - 'traits': ['base', 'robot'], - 'state': { - 'base': { 'firmwareVersion': '1.0' } + 'comp': { + 'traits': ['base', 'robot'], + 'state': { + 'base': { 'firmwareVersion': '1.0' } + } } - } - })"; + })"; EXPECT_JSON_EQ(expectedComponents, *dict); base::DictionaryValue json_resp;