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;