记一次Cloud调试经历
目标
连接移动物联网开放平台,Publish传感器数据到托管程序。
开发环境
只有VS2017社区版;采用MVC Model View Controller5, OpenNET非常适合入门因为文档非常具有实操性,无论从应用层还是设备开发来说都没问题。
学习MVC
msdn有不错的教程,就是Movie List 那个。Controller 类是ACTION和Route方法的核心;视图用所谓Razor语法实现脚本能力,可以,通过ViewData或者ViewBag静态方法和控制器传递数据
整体框架
只传单点值到IoT平台的设备DataStream 上。需要借助HTTP POST方法;
除了Controller和View我还不想引入DB,因此设计一个表示服务端JSON 字串明示的结构信息;
用户输入通过本地IIS host 网页转达云端IoT;
没有单元测试;
MQTT
因为我读过MQTT协议知道这意味着在ICD 这个章节可以得到精确的POST方法header和必须配置的参数。MQTT建立在TCP连接基础上类似HTTP那样,核心是QoS等级可以近似保证必达性(?)也就是实时消息流加无限重传确保关键信息不丢失。
POST
没有提到的参数例如Host等千万不要画蛇添足加上去否则服务器总是返回我404找不到设备,400语法错误。云端的设计还比较RESTful 所以这里唯一的问题走JavaScript还是ASP.Net 或者 HttpWebRequest?年少的你会选前者,我还是借用微软类库做吧。
JSON转义到类
喏就是这样的DS,DP,这次的定义非常简洁直达核心
public class DataStreams
{
public DataStream[] datastreams
{
get;set;
}
public static string ToString(DataStreams t)
{
JavaScriptSerializer jsonSerialize = new JavaScriptSerializer();
return jsonSerialize.Serialize(t);
}
}
public class DataStream
{
public string id
{
get; set;
}
public DataPoint[] datapoints
{
get;set;
}
}
public class DataPoint
{
public string at//DateTime
{
get;set;
}
public double value
{
get;set;
}
}
创建
因为今天下午刚刚看了CC01所以用这个好词。建一个MVC工程并右键添加一个BridgeController和对应目录下的Publish.cshtml View.
View类下连接一下C
@using (Html.BeginForm("Publish", "Bridge"))
{
<p>
<p>
Url:@Html.TextBox("Url")
</p>
<p>
Device ID:@Html.TextBox("DeviceID")
</p>
<p>
APIKey:@Html.TextBox("APIKey")
</p>
<p>
DataStream:@Html.TextBox("DataStream")
</p>
<p>
Values:@Html.TextBox("Values")
</p>
</p>
<input type="submit" value="Post" />
}
这样数据就可以从我们的页面视图Post到C的方法,方法利用页面上用户输入的信息构建了一个JSON对象,Publish回调方法看起来
public ActionResult Publish()
{
var device_id = Request.Form["DeviceID"];
if (!string.IsNullOrEmpty(device_id)) {
var temp = new PostRequest()
{
Url = string.Format("http://api.heclouds.com/devices/{0}/datapoints ", device_id),
ApiKey = Request.Form["APIKey"],
DataStream = Request.Form["DataStream"],
Value = Request.Form["Values"],
PeriodicInterval = Request.Form["PeriodicInterval"],
};
// Update View
ViewBag.TestString = this.SyncPublish(temp);
}
return View();
}
这里的命名SyncPublish的含义是把原本异步的HttpRequest 在这里处理成同步的,一个简化版本可以是
private string SyncPublish(PostRequest pr)
{
var ds = new DataStream() {
id = "Dimensional",
datapoints = new DataPoint[] {
new DataPoint() { at = DateTime.Now.ToString("yyyy-MM-ddThh:mm:ss"), value = Convert.ToDouble(pr.Value) },
//new DataPoint() { at = DateTime.Now.ToString("YYYY-MM-DDThh:mm:ss"), value = Convert.ToDouble(pr.Value) },
}
};
var dss = new DataStreams() { datastreams = new DataStream[] { ds } };
var content = DataStreams.ToString(dss);
byte[] buffer = Encoding.UTF8.GetBytes(content);
HttpWebRequest rq = (HttpWebRequest)WebRequest.Create(pr.Url);
rq.Method = "POST";
rq.ContentType = "text/html";
rq.ContentLength = buffer.Length;
SetHeaderValue(rq.Headers, "api-key", pr.ApiKey);
var output = rq.GetRequestStream();
output.Write(buffer, 0, buffer.Length);
HttpWebResponse resp = (HttpWebResponse)rq.GetResponse();
using (Stream stream = resp.GetResponseStream())
{
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
string responseString = reader.ReadToEnd();
return responseString;
}
}
开始一堆准备内容,我的DS名称叫做Dimensional,一看就是数组做多了;中间,准备POST数据块;最后一段同步接收。出错处理就是简单的崩掉。
数据和界面分离
刚才写到一半我想把我的APIKey打马赛克,结果发现不用,因为读取的用户输入,索诺斯内不经意我竟然实现了分离,啧啧
继续创建,调试
Fine在一个小时内想明白了404 和400错误代码后程序开始工作;感谢程序猿给世界带来的和平和安宁。
总结
MQTT不难
HTTP 不难
IoT应用不难
Cloud数据存储不难
调试不难
软件不难
难的还是数据价值
不过作为好奇的程序员我可以继续研究OPenNET中的设备端MQTT协议实现。