24个版本
0.15.2 | 2022年10月1日 |
---|---|
0.15.0 | 2022年3月9日 |
0.14.0 | 2021年1月5日 |
0.13.2 | 2020年12月30日 |
0.7.0 | 2018年7月20日 |
#149 in HTTP服务器
214 每月下载次数
用于 somfy
94KB
2K SLoC
webthing
HTTP Web Thing的实现。
使用
如果你使用 Cargo
,只需将 webthing
添加到你的 Cargo.toml
[dependencies]
webthing = "0.15"
TLS支持
如果你需要服务器端的TLS支持,你需要使用 ssl
功能集进行编译。
示例
在这个示例中,我们将设置一个可调光的灯和一个湿度传感器(当然,两者都使用假数据)。两个工作示例可以在 这里 找到。
可调光灯
想象一下,你有一个可以调光的灯,你想通过物联网API公开它。该灯可以开启/关闭,并且可以从0%到100%设置亮度。除了名称、描述和类型外,一个 Light
还需要公开两个属性
on
: 灯的状态,是否开启或关闭- 通过REST API的PUT调用设置此属性,可以通过调用
PUT {"on": true/false}
来切换灯的开关。
- 通过REST API的PUT调用设置此属性,可以通过调用
brightness
: 灯的亮度级别,从0-100%- 通过PUT调用REST API设置此属性可以设置该灯的亮度级别。
首先创建一个新的Thing
let mut light = BaseThing::new(
"urn:dev:ops:my-lamp-1234".to_owned(),
"My Lamp".to_owned(),
Some(vec!["OnOffSwitch".to_owned(), "Light".to_owned()]),
Some("A web connected lamp".to_owned()),
);
现在我们可以添加所需的属性。
on
属性报告并设置灯的开关状态。对我们来说,我们只想在灯打开/关闭时记录新状态。
struct OnValueForwarder;
impl ValueForwarder for OnValueForwarder {
fn set_value(&mut self, value: serde_json::Value) -> Result<serde_json::Value, &'static str> {
println!("On-State is now {}", value);
Ok(value)
}
}
let on_description = json!({
"@type": "OnProperty",
"title": "On/Off",
"type": "boolean",
"description": "Whether the lamp is turned on"
});
let on_description = on_description.as_object().unwrap().clone();
thing.add_property(Box::new(BaseProperty::new(
"on".to_owned(),
json!(true),
Some(Box::new(OnValueForwarder)),
Some(on_description),
)));
亮度
属性报告光的亮度级别并设置该级别。和以前一样,我们不是真正设置光的级别,而是记录该级别。
struct BrightnessValueForwarder;
impl ValueForwarder for BrightnessValueForwarder {
fn set_value(&mut self, value: serde_json::Value) -> Result<serde_json::Value, &'static str> {
println!("Brightness is now {}", value);
Ok(value)
}
}
let brightness_description = json!({
"@type": "BrightnessProperty",
"title": "Brightness",
"type": "number",
"description": "The level of light from 0-100",
"minimum": 0,
"maximum": 100,
"unit": "percent"
});
let brightness_description = brightness_description.as_object().unwrap().clone();
thing.add_property(Box::new(BaseProperty::new(
"brightness".to_owned(),
json!(50),
Some(Box::new(BrightnessValueForwarder)),
Some(brightness_description),
)));
现在我们可以将我们新创建的事物添加到服务器并启动它
let mut things: Vec<Arc<RwLock<Box<dyn Thing + 'static>>>> = Vec::new();
things.push(Arc::new(RwLock::new(Box::new(light)));
// If adding more than one thing, use ThingsType::Multiple() with a name.
// In the single thing case, the thing's name will be broadcast.
let mut server = WebThingServer::new(
ThingsType::Multiple(things, "LightAndTempDevice".to_owned()),
Some(8888),
None,
None,
Box::new(Generator),
None,
None,
);
let server_addr = server.create();
server.start();
这将启动服务器,通过 WoT REST API 使灯光可用,并通过 mDNS 在您的本地网络上宣布其为可发现资源。
传感器
现在让我们也将湿度传感器连接到我们为灯光设置的服务器。
MultiLevelSensor
(返回级别而不是仅开/关的传感器)有一个必需的属性(除了名称、类型和可选描述之外):level
。我们想监视这个属性,并在值更改时接收通知。
首先创建一个新的Thing
let mut thing = BaseThing::new(
"urn:dev:ops:my-humidity-sensor-1234".to_owned(),
"My Humidity Sensor".to_owned(),
Some(vec!["MultiLevelSensor".to_owned()]),
Some("A web connected humidity sensor".to_owned()),
);
然后我们创建并添加适当的属性
-
level
:告诉我们传感器实际读取的内容- 与灯光相反,值不能通过 API 调用来设置,因为这没有太多意义,设置传感器正在读取的内容。因此,我们正在创建一个 只读 属性。
let level_description = json!({ "@type": "LevelProperty", "title": "Humidity", "type": "number", "description": "The current humidity in %", "minimum": 0, "maximum": 100, "unit": "percent", "readOnly": true }); let level_description = level_description.as_object().unwrap().clone(); thing.add_property(Box::new(BaseProperty::new( "level".to_owned(), json!(0), None, Some(level_description), )));
现在我们有一个传感器,它不断报告 0%。为了使其可用,我们需要一个线程或某种类型的输入,当传感器有新的读取可用时。为此,我们启动一个线程,每隔几秒钟查询物理传感器。对于我们的目的,它只是调用一个假方法。
let sensor = Arc::new(RwLock::new(Box::new(sensor))));
let cloned = sensor.clone();
thread::spawn(move || {
let mut rng = rand::thread_rng();
// Mimic an actual sensor updating its reading every couple seconds.
loop {
thread::sleep(time::Duration::from_millis(3000));
let t = cloned.clone();
let new_value = json!(
70.0 * rng.gen_range::<f32>(0.0, 1.0) * (-0.5 + rng.gen_range::<f32>(0.0, 1.0))
);
{
let mut t = t.write().unwrap();
let prop = t.find_property("level".to_owned()).unwrap();
let _ = prop.set_value(new_value.clone());
}
t.write()
.unwrap()
.property_notify("level".to_owned(), new_value);
}
});
这将使用随机的传感器读取来更新我们的属性。然后,将新的属性值发送到所有 WebSocket 听众。
添加到网关
要将您的 Web 事物添加到 WebThings Gateway,请安装“Web Thing”插件并按照此处的说明操作。
依赖关系
~13–27MB
~467K SLoC