Add Csharp and Bash/Curl/Node.js versions of Http device telemetry

This commit is contained in:
Oguz Bastemur 2018-12-05 16:33:57 -08:00
Родитель 4eb2cbf38f
Коммит 55ed4b98c6
7 изменённых файлов: 767 добавлений и 0 удалений

124
HttpOnly/Bash/README.md Normal file
Просмотреть файл

@ -0,0 +1,124 @@
### Connecting to Azure IoT Central via HTTP (bash/curl/node)
If you want to jump directly to example script without the explanations,
[click here](dobash.sh)
```
DEVICE_ID="ENTER DEVICE ID HERE"
DEVICE_KEY="ENTER DEVICE SYM KEY HERE"
SCOPE="ENTER SCOPE ID HERE"
MESSAGE='{"temp":15}' # <=== your telemetry goes here
```
Open [apps.azureiotcentral.com](apps.azureiotcentral.com) `>` Device Explorer (explorer)
`>` Select one of the templates (i.e. MXCHIP) `>` Click to `+` button on the tab `>`
Select `Real device`
You should see a `Connect` link on top-right of the device page. Once you click
to that button, you will find all the `DEVICE_ID`, `DEVICE_KEY` (Primary_key) and
`SCOPE_ID` there.
Now, we need to generate the authentication header for our requests. Please take
a look at the basic BASH function below. It executes a node script and uses the
arguments we collected from the device page.
```
function getAuth {
# A node script that prints an auth signature using SCOPE, DEVICE_ID and DEVICE_KEY
AUTH=`node -e "\
const crypto = require('crypto');\
function computeDrivedSymmetricKey(masterKey, regId) {\
return crypto.createHmac('SHA256', Buffer.from(masterKey, 'base64'))\
.update(regId, 'utf8')\
.digest('base64');\
}\
\
var expires = parseInt((Date.now() + (7200 * 1000)) / 1000);\
var sr = '${SCOPE}%2f${TARGET}%2f${DEVICE_ID}';\
var sigNoEncode = computeDrivedSymmetricKey('${DEVICE_KEY}', sr + '\n' + expires);\
var sigEncoded = encodeURIComponent(sigNoEncode);\
console.log('SharedAccessSignature sr=' + sr + '&sig=' + sigEncoded + '&se=' + expires)\
"`
}
SCOPEID="$SCOPE"
TARGET="registrations"
# get auth for Azure IoT DPS service
getAuth
```
We will make the first DPS call. This call will provide us the `operationId`
```
# use the Auth and make a PUT request to Azure IoT DPS service
curl \
-H "authorization: ${AUTH}&skn=registration" \
-H 'content-type: application/json; charset=utf-8' -H 'content-length: 25' \
-s -o output.txt \
--request PUT --data "{\"registrationId\":\"$DEVICE_ID\"}" "https://global.azure-devices-provisioning.net/$SCOPEID/registrations/$DEVICE_ID/register?api-version=2018-11-01"
OPERATION=`node -e "fs=require('fs');c=fs.readFileSync('./output.txt')+'';c=JSON.parse(c);if(c.errorCode){console.log(c);process.exit(1);}console.log(c.operationId)"`
if [[ $? != 0 ]]; then
# if there was an error, print the stdout part and exit
echo "$OPERATION"
exit
else
echo "Authenticating.."
# wait 2 secs before making the GET request to Azure IoT DPS service
# the second call will bring us the Azure IoT Hub endpoint we are supposed to talk
sleep 2
```
Now, we are going to make the second DPS call. This call will give us the Azure IoT hub
hostname. Using that hostname and our device key, we will create the authentication
key for our iothub telemetry message.
```
OUT=`curl -s \
-H "authorization: ${AUTH}&skn=registration" \
-H "content-type: application/json; charset=utf-8" \
--request GET "https://global.azure-devices-provisioning.net/$SCOPEID/registrations/$DEVICE_ID/operations/$OPERATION?api-version=2018-11-01"`
# parse the return value from the DPS host and try to grab the assigned hub
OUT=`node -pe "a=JSON.parse('$OUT');if(a.errorCode){a}else{a.registrationState.assignedHub}"`
if [[ $OUT =~ 'errorCode' ]]; then
# if there was an error, print the stdout part and exit
echo "$OUT"
exit
fi
```
Finally generate the Azure IoT hub authentication key using the hostname that
we received from DPS.
```
TARGET="devices"
SCOPE="$OUT"
# get Auth for Azure IoThub service
getAuth
echo "OK"
echo
```
It's time to send our telemetry to Azure IoT Hub
```
echo "SENDING => " $MESSAGE
# send a telemetry to Azure IoT hub service
curl -s \
-H "authorization: ${AUTH}" \
-H "iothub-to: /devices/$DEVICE_ID/messages/events" \
--request POST --data "$MESSAGE" "https://$SCOPE/devices/$DEVICE_ID/messages/events/?api-version=2016-11-14"
echo "DONE"
fi
echo
```
Turn back to Azure IoT central and browse the device page. You should see `temperature` telemetry soon.

85
HttpOnly/Bash/dobash.sh Executable file
Просмотреть файл

@ -0,0 +1,85 @@
#/bin/bash
DEVICE_ID="ENTER DEVICE ID HERE"
DEVICE_KEY="ENTER DEVICE SYM KEY HERE"
SCOPE="ENTER SCOPE ID HERE"
MESSAGE='{"temp":15}'
function getAuth {
# A node script that prints an auth signature using SCOPE, DEVICE_ID and DEVICE_KEY
AUTH=`node -e "\
const crypto = require('crypto');\
function computeDrivedSymmetricKey(masterKey, regId) {\
return crypto.createHmac('SHA256', Buffer.from(masterKey, 'base64'))\
.update(regId, 'utf8')\
.digest('base64');\
}\
\
var expires = parseInt((Date.now() + (7200 * 1000)) / 1000);\
var sr = '${SCOPE}%2f${TARGET}%2f${DEVICE_ID}';\
var sigNoEncode = computeDrivedSymmetricKey('${DEVICE_KEY}', sr + '\n' + expires);\
var sigEncoded = encodeURIComponent(sigNoEncode);\
console.log('SharedAccessSignature sr=' + sr + '&sig=' + sigEncoded + '&se=' + expires)\
"`
}
SCOPEID="$SCOPE"
TARGET="registrations"
# get auth for Azure IoT DPS service
getAuth
# use the Auth and make a PUT request to Azure IoT DPS service
OUT=`curl \
-H "authorization: ${AUTH}&skn=registration" \
-H 'content-type: application/json; charset=utf-8' -H 'content-length: 25' \
-s \
--request PUT --data "{\"registrationId\":\"$DEVICE_ID\"}" "https://global.azure-devices-provisioning.net/$SCOPEID/registrations/$DEVICE_ID/register?api-version=2018-11-01"`
OPERATION=`node -e "c=JSON.parse('$OUT');if(c.errorCode){console.log(c);process.exit(1);}console.log(c.operationId)"`
if [[ $? != 0 ]]; then
# if there was an error, print the stdout part and exit
echo "$OPERATION"
exit
else
echo "Authenticating.."
# wait 2 secs before making the GET request to Azure IoT DPS service
# the second call will bring us the Azure IoT Hub endpoint we are supposed to talk
sleep 2
OUT=`curl -s \
-H "authorization: ${AUTH}&skn=registration" \
-H "content-type: application/json; charset=utf-8" \
--request GET "https://global.azure-devices-provisioning.net/$SCOPEID/registrations/$DEVICE_ID/operations/$OPERATION?api-version=2018-11-01"`
# parse the return value from the DPS host and try to grab the assigned hub
OUT=`node -pe "a=JSON.parse('$OUT');if(a.errorCode){a}else{a.registrationState.assignedHub}"`
if [[ $OUT =~ 'errorCode' ]]; then
# if there was an error, print the stdout part and exit
echo "$OUT"
exit
fi
TARGET="devices"
SCOPE="$OUT"
# get Auth for Azure IoThub service
getAuth
echo "OK"
echo
echo "SENDING => " $MESSAGE
# send a telemetry to Azure IoT hub service
curl -s \
-H "authorization: ${AUTH}" \
-H "iothub-to: /devices/$DEVICE_ID/messages/events" \
--request POST --data "$MESSAGE" "https://$SCOPE/devices/$DEVICE_ID/messages/events/?api-version=2016-11-14"
echo "DONE"
fi
echo

1
HttpOnly/CSharp/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
app.exe

Просмотреть файл

@ -0,0 +1,371 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
namespace TinyJson
{
// Really simple JSON parser in ~300 lines
// - Attempts to parse JSON files with minimal GC allocation
// - Nice and simple "[1,2,3]".FromJson<List<int>>() API
// - Classes and structs can be parsed too!
// class Foo { public int Value; }
// "{\"Value\":10}".FromJson<Foo>()
// - Can parse JSON without type information into Dictionary<string,object> and List<object> e.g.
// "[1,2,3]".FromJson<object>().GetType() == typeof(List<object>)
// "{\"Value\":10}".FromJson<object>().GetType() == typeof(Dictionary<string,object>)
// - No JIT Emit support to support AOT compilation on iOS
// - Attempts are made to NOT throw an exception if the JSON is corrupted or invalid: returns null instead.
// - Only public fields and property setters on classes/structs will be written to
//
// Limitations:
// - No JIT Emit support to parse structures quickly
// - Limited to parsing <2GB JSON files (due to int.MaxValue)
// - Parsing of abstract classes or interfaces is NOT supported and will throw an exception.
public static class JSONParser
{
[ThreadStatic] static Stack<List<string>> splitArrayPool;
[ThreadStatic] static StringBuilder stringBuilder;
[ThreadStatic] static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfoCache;
[ThreadStatic] static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyInfoCache;
public static T FromJson<T>(this string json)
{
// Initialize, if needed, the ThreadStatic variables
if (propertyInfoCache == null) propertyInfoCache = new Dictionary<Type, Dictionary<string, PropertyInfo>>();
if (fieldInfoCache == null) fieldInfoCache = new Dictionary<Type, Dictionary<string, FieldInfo>>();
if (stringBuilder == null) stringBuilder = new StringBuilder();
if (splitArrayPool == null) splitArrayPool = new Stack<List<string>>();
//Remove all whitespace not within strings to make parsing simpler
stringBuilder.Length = 0;
for (int i = 0; i < json.Length; i++)
{
char c = json[i];
if (c == '"')
{
i = AppendUntilStringEnd(true, i, json);
continue;
}
if (char.IsWhiteSpace(c))
continue;
stringBuilder.Append(c);
}
//Parse the thing!
return (T)ParseValue(typeof(T), stringBuilder.ToString());
}
static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json)
{
stringBuilder.Append(json[startIdx]);
for (int i = startIdx+1; i<json.Length; i++)
{
if (json[i] == '\\')
{
if (appendEscapeCharacter)
stringBuilder.Append(json[i]);
stringBuilder.Append(json[i + 1]);
i++;//Skip next character as it is escaped
}
else if (json[i] == '"')
{
stringBuilder.Append(json[i]);
return i;
}
else
stringBuilder.Append(json[i]);
}
return json.Length - 1;
}
//Splits { <value>:<value>, <value>:<value> } and [ <value>, <value> ] into a list of <value> strings
static List<string> Split(string json)
{
List<string> splitArray = splitArrayPool.Count > 0 ? splitArrayPool.Pop() : new List<string>();
splitArray.Clear();
if(json.Length == 2)
return splitArray;
int parseDepth = 0;
stringBuilder.Length = 0;
for (int i = 1; i<json.Length-1; i++)
{
switch (json[i])
{
case '[':
case '{':
parseDepth++;
break;
case ']':
case '}':
parseDepth--;
break;
case '"':
i = AppendUntilStringEnd(true, i, json);
continue;
case ',':
case ':':
if (parseDepth == 0)
{
splitArray.Add(stringBuilder.ToString());
stringBuilder.Length = 0;
continue;
}
break;
}
stringBuilder.Append(json[i]);
}
splitArray.Add(stringBuilder.ToString());
return splitArray;
}
internal static object ParseValue(Type type, string json)
{
if (type == typeof(string))
{
if (json.Length <= 2)
return string.Empty;
StringBuilder parseStringBuilder = new StringBuilder(json.Length);
for (int i = 1; i<json.Length-1; ++i)
{
if (json[i] == '\\' && i + 1 < json.Length - 1)
{
int j = "\"\\nrtbf/".IndexOf(json[i + 1]);
if (j >= 0)
{
parseStringBuilder.Append("\"\\\n\r\t\b\f/"[j]);
++i;
continue;
}
if (json[i + 1] == 'u' && i + 5 < json.Length - 1)
{
UInt32 c = 0;
if (UInt32.TryParse(json.Substring(i + 2, 4), System.Globalization.NumberStyles.AllowHexSpecifier, null, out c))
{
parseStringBuilder.Append((char)c);
i += 5;
continue;
}
}
}
parseStringBuilder.Append(json[i]);
}
return parseStringBuilder.ToString();
}
if (type.IsPrimitive)
{
var result = Convert.ChangeType(json, type, System.Globalization.CultureInfo.InvariantCulture);
return result;
}
if (type == typeof(decimal))
{
decimal result;
decimal.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out result);
return result;
}
if (json == "null")
{
return null;
}
if (type.IsEnum)
{
if (json[0] == '"')
json = json.Substring(1, json.Length - 2);
try
{
return Enum.Parse(type, json, false);
}
catch
{
return 0;
}
}
if (type.IsArray)
{
Type arrayType = type.GetElementType();
if (json[0] != '[' || json[json.Length - 1] != ']')
return null;
List<string> elems = Split(json);
Array newArray = Array.CreateInstance(arrayType, elems.Count);
for (int i = 0; i < elems.Count; i++)
newArray.SetValue(ParseValue(arrayType, elems[i]), i);
splitArrayPool.Push(elems);
return newArray;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
Type listType = type.GetGenericArguments()[0];
if (json[0] != '[' || json[json.Length - 1] != ']')
return null;
List<string> elems = Split(json);
var list = (IList)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count });
for (int i = 0; i < elems.Count; i++)
list.Add(ParseValue(listType, elems[i]));
splitArrayPool.Push(elems);
return list;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
Type keyType, valueType;
{
Type[] args = type.GetGenericArguments();
keyType = args[0];
valueType = args[1];
}
//Refuse to parse dictionary keys that aren't of type string
if (keyType != typeof(string))
return null;
//Must be a valid dictionary element
if (json[0] != '{' || json[json.Length - 1] != '}')
return null;
//The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
return null;
var dictionary = (IDictionary)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count / 2 });
for (int i = 0; i < elems.Count; i += 2)
{
if (elems[i].Length <= 2)
continue;
string keyValue = elems[i].Substring(1, elems[i].Length - 2);
object val = ParseValue(valueType, elems[i + 1]);
dictionary.Add(keyValue, val);
}
return dictionary;
}
if (type == typeof(object))
{
return ParseAnonymousValue(json);
}
if (json[0] == '{' && json[json.Length - 1] == '}')
{
return ParseObject(type, json);
}
return null;
}
public static object ParseAnonymousValue(string json)
{
if (json.Length == 0)
return null;
if (json[0] == '{' && json[json.Length - 1] == '}')
{
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
return null;
var dict = new Dictionary<string, object>(elems.Count / 2);
for (int i = 0; i < elems.Count; i += 2)
dict.Add(elems[i].Substring(1, elems[i].Length - 2), ParseAnonymousValue(elems[i + 1]));
return dict;
}
if (json[0] == '[' && json[json.Length - 1] == ']')
{
List<string> items = Split(json);
var finalList = new List<object>(items.Count);
for (int i = 0; i < items.Count; i++)
finalList.Add(ParseAnonymousValue(items[i]));
return finalList;
}
if (json[0] == '"' && json[json.Length - 1] == '"')
{
string str = json.Substring(1, json.Length - 2);
return str.Replace("\\", string.Empty);
}
if (char.IsDigit(json[0]) || json[0] == '-')
{
if (json.Contains("."))
{
double result;
double.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out result);
return result;
}
else
{
int result;
int.TryParse(json, out result);
return result;
}
}
if (json == "true")
return true;
if (json == "false")
return false;
// handles json == "null" as well as invalid JSON
return null;
}
static Dictionary<string, T> CreateMemberNameDictionary<T>(T[] members) where T : MemberInfo
{
Dictionary<string, T> nameToMember = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
for (int i = 0; i < members.Length; i++)
{
T member = members[i];
if (member.IsDefined(typeof(IgnoreDataMemberAttribute), true))
continue;
string name = member.Name;
if (member.IsDefined(typeof(DataMemberAttribute), true))
{
DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)Attribute.GetCustomAttribute(member, typeof(DataMemberAttribute), true);
if (!string.IsNullOrEmpty(dataMemberAttribute.Name))
name = dataMemberAttribute.Name;
}
nameToMember.Add(name, member);
}
return nameToMember;
}
static object ParseObject(Type type, string json)
{
object instance = FormatterServices.GetUninitializedObject(type);
//The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
return instance;
Dictionary<string, FieldInfo> nameToField;
Dictionary<string, PropertyInfo> nameToProperty;
if (!fieldInfoCache.TryGetValue(type, out nameToField))
{
nameToField = CreateMemberNameDictionary(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
fieldInfoCache.Add(type, nameToField);
}
if (!propertyInfoCache.TryGetValue(type, out nameToProperty))
{
nameToProperty = CreateMemberNameDictionary(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
propertyInfoCache.Add(type, nameToProperty);
}
for (int i = 0; i < elems.Count; i += 2)
{
if (elems[i].Length <= 2)
continue;
string key = elems[i].Substring(1, elems[i].Length - 2);
string value = elems[i + 1];
FieldInfo fieldInfo;
PropertyInfo propertyInfo;
if (nameToField.TryGetValue(key, out fieldInfo))
fieldInfo.SetValue(instance, ParseValue(fieldInfo.FieldType, value));
else if (nameToProperty.TryGetValue(key, out propertyInfo))
propertyInfo.SetValue(instance, ParseValue(propertyInfo.PropertyType, value), null);
}
return instance;
}
}
}

48
HttpOnly/CSharp/LICENSE Normal file
Просмотреть файл

@ -0,0 +1,48 @@
The MIT License (MIT)
Copyright (c) Microsoft Corporation
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- TinyJson
Copyright (c) 2013 Patrick Hogan
Based on MiniJSON by Calvin Rien https://gist.github.com/darktable/1411710
Based on the JSON parser by Patrick van Bergen http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in the
Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

23
HttpOnly/CSharp/README.md Normal file
Просмотреть файл

@ -0,0 +1,23 @@
### Connecting to Azure IoT Central via HTTP (C#)
To Run;
```
csc app.cs JSONParser.cs
```
and then execute `app.exe`
Don't forget filling the required variables under `app.cs`
```
string scopeId = "ENTER SCOPE ID HERE";
string deviceId = "ENTER DEVICE ID HERE";
string deviceKey = "ENTER DEVICE KEY HERE=";
```
Open [apps.azureiotcentral.com](apps.azureiotcentral.com) `>` Device Explorer (explorer)
`>` Select one of the templates (i.e. MXCHIP) `>` Click to `+` button on the tab `>`
Select `Real device`
You should see a `Connect` link on top-right of the device page. Once you click
to that button, you will find all the `deviceId`, `deviceKey` (Primary_key) and
`scopeId` there.

115
HttpOnly/CSharp/app.cs Normal file
Просмотреть файл

@ -0,0 +1,115 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Net;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using TinyJson;
public class IoTCentralDemo
{
string scopeId = "Enter SCOPE ID here";
string deviceId = "Enter DEVICE ID here";
string deviceKey = "Enter DEVICE KEY here";
string computeHash(string key, string Id) {
HMACSHA256 hmac = new HMACSHA256(System.Convert.FromBase64String(key));
return System.Convert.ToBase64String(hmac.ComputeHash(Encoding.ASCII.GetBytes(Id)));
}
string getAuth(string scope, string target) {
long utcTimeInMilliseconds = DateTime.UtcNow.Ticks / 10000;
long expires = ((utcTimeInMilliseconds + (7200 * 1000)) / 1000);
string sr = scope + "%2f" + target + "%2f" + deviceId;
string sigNoEncode = computeHash(deviceKey, sr + '\n' + expires.ToString());
string sigEncoded = Uri.EscapeDataString(sigNoEncode);
return "SharedAccessSignature sr=" + sr + "&sig=" + sigEncoded + "&se=" + expires.ToString();
}
public string MakeRequest(string method, string payload, string authScope, string address, bool isDPS)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
request.Method = method;
request.ContentType = "application/json";
string authTarget = "";
string reason = "";
if (isDPS) {
reason = "registrations";
authTarget = "&skn=registration";
} else {
reason = "devices";
request.Headers.Add("iothub-to", "/devices/" + deviceId + "/messages/events");
}
request.Headers.Add("Authorization", getAuth(authScope, reason) + authTarget);
if (payload.Length > 0) {
request.ContentLength = payload.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(Encoding.ASCII.GetBytes(payload), 0, payload.Length);
dataStream.Close();
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream receiveStream = response.GetResponseStream();
Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
StreamReader readStream = new StreamReader( receiveStream, encode );
return readStream.ReadToEnd(); // bad hack
}
public void Run() {
// get operationId from Azure IoT DPS
string address = "https://global.azure-devices-provisioning.net/" + scopeId + "/registrations/" + deviceId + "/register?api-version=2018-11-01";
string json = MakeRequest("PUT", "{\"registrationId\":\"" + deviceId + "\"}", scopeId, address, true);
var obj = json.FromJson<object>();
Dictionary<string,object> dict = (Dictionary<string,object>)obj;
if (dict.ContainsKey("errorCode")) {
Console.WriteLine("ERROR: " + json);
return;
}
string operationId = dict["operationId"].ToString();
// Using the operationId and the rest of the credentials, get hostname for the Azure IoT hub
// The reason for the loop is that the async op. we had triggered with the operationId request
// may take more than 2secs.
// So, wait for 2 secs+ each time and then try again
for (int i = 0; i < 10; i++) // try 5 times
{
System.Threading.Thread.Sleep(2500);
address = "https://global.azure-devices-provisioning.net/" + scopeId + "/registrations/" + deviceId + "/operations/" + operationId + "?api-version=2018-11-01";
json = MakeRequest("GET", "", scopeId, address, true);
obj = json.FromJson<object>();
dict = (Dictionary<string,object>)obj;
if (dict.ContainsKey("errorCode")) {
Console.WriteLine("ERROR: " + json);
return;
}
if (dict.ContainsKey("registrationState")) {
if ( ((Dictionary<string,object>)dict["registrationState"]).ContainsKey("assignedHub"))
break;
}
}
string hostName = ((Dictionary<string,object>)dict["registrationState"])["assignedHub"].ToString();
// finally, send our temperature telemetry to Azure IoT Hub
address = "https://" + hostName + "/devices/" + deviceId + "/messages/events/?api-version=2016-11-14";
json = MakeRequest("POST", "{\"temp\" : 15}", hostName, address, false);
if (json.Length == 0) {
Console.WriteLine("Success!! Check the new temperature telemetry on Azure IoT Central Device window");
} else {
Console.WriteLine(json);
}
}
static void Main() {
IoTCentralDemo demo = new IoTCentralDemo();
demo.Run();
}
}