Skip to content

Instantly share code, notes, and snippets.

@ma2shita
Last active February 20, 2019 18:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ma2shita/4a43d39a8d61f6be8f1163050498e498 to your computer and use it in GitHub Desktop.
Save ma2shita/4a43d39a8d61f6be8f1163050498e498 to your computer and use it in GitHub Desktop.
See: https://qiita.com/ma2shita/items/8f1b4b12faa99dd17063 | Monitoring ThingShadow in AWS IoT Core using Websocket
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Call monitor</title>
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/vue-i18n/dist/vue-i18n.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/aws-sdk/2.404.0/aws-sdk.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.2/mqttws31.min.js"></script>
<!-- UIkit CSS -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/uikit/3.0.3/css/uikit.min.css" />
<script>/* from https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/protocols.html */
/**
* utilities to do sigv4
* @class SigV4Utils
*/
function SigV4Utils() { }
SigV4Utils.getSignatureKey = function (key, date, region, service) {
var kDate = AWS.util.crypto.hmac('AWS4' + key, date, 'buffer');
var kRegion = AWS.util.crypto.hmac(kDate, region, 'buffer');
var kService = AWS.util.crypto.hmac(kRegion, service, 'buffer');
var kCredentials = AWS.util.crypto.hmac(kService, 'aws4_request', 'buffer');
return kCredentials;
};
SigV4Utils.getSignedUrl = function (host, region, credentials) {
var datetime = AWS.util.date.iso8601(new Date()).replace(/[:\-]|\.\d{3}/g, '');
var date = datetime.substr(0, 8);
var method = 'GET';
var protocol = 'wss';
var uri = '/mqtt';
var service = 'iotdevicegateway';
var algorithm = 'AWS4-HMAC-SHA256';
var credentialScope = date + '/' + region + '/' + service + '/' + 'aws4_request';
var canonicalQuerystring = 'X-Amz-Algorithm=' + algorithm;
canonicalQuerystring += '&X-Amz-Credential=' + encodeURIComponent(credentials.accessKeyId + '/' + credentialScope);
canonicalQuerystring += '&X-Amz-Date=' + datetime;
canonicalQuerystring += '&X-Amz-SignedHeaders=host';
var canonicalHeaders = 'host:' + host + '\n';
var payloadHash = AWS.util.crypto.sha256('', 'hex')
var canonicalRequest = method + '\n' + uri + '\n' + canonicalQuerystring + '\n' + canonicalHeaders + '\nhost\n' + payloadHash;
var stringToSign = algorithm + '\n' + datetime + '\n' + credentialScope + '\n' + AWS.util.crypto.sha256(canonicalRequest, 'hex');
var signingKey = SigV4Utils.getSignatureKey(credentials.secretAccessKey, date, region, service);
var signature = AWS.util.crypto.hmac(signingKey, stringToSign, 'hex');
canonicalQuerystring += '&X-Amz-Signature=' + signature;
if (credentials.sessionToken) {
canonicalQuerystring += '&X-Amz-Security-Token=' + encodeURIComponent(credentials.sessionToken);
}
var requestUrl = protocol + '://' + host + uri + '?' + canonicalQuerystring;
return requestUrl;
};
</script>
<style>
.status {
font-size: 2.2rem;
padding-top: 5rem;
padding-left: 1rem;
}
</style>
</head>
<body>
<div id="app1">
<div class="uk-section uk-padding-remove-vertical uk-section-muted">
<div clss="uk-container uk-container-expand">
<div uk-grid class="uk-grid-collapse">
<div class="uk-width-1-3">
<img src="https://docs.google.com/drawings/d/e/2PACX-1vS0Xcd447K0qwF0cfpv-TgWCsMccm4VUw2zSUN9PH5vadizscbd9FyWegUxP6YbFwSJ6hLUK7fDaGeE/pub?w=812&h=554">
</div>
<div class="uk-width-1-3">
<img src="https://docs.google.com/drawings/d/e/2PACX-1vRvOPH3QJ1lnBQQpBT6T5_fE6Dg9P9XzXWHjqkSbuqbp5U40x5eEfXC7F70An7Me0UwOtHZiZmBljtt/pub?w=812&h=554">
</div>
<div class="uk-width-1-3 status">
{{ $t(members["soracom_max"]) }}
</div>
</div>
</div>
</div>
<div class="uk-section uk-padding-remove-vertical uk-section-secondary">
<div clss="uk-container uk-container-expand">
<div uk-grid class="uk-grid-collapse">
<div class="uk-width-1-3">
<img src="https://docs.google.com/drawings/d/e/2PACX-1vQw3stGVwjr64T8gxmXNSCMr4gk3fmPrhJHrGJQWCxiJP7svgigJ0VazWPmMKBOCyvxtLRMNJ-5cxfL/pub?w=812&h=554">
</div>
<div class="uk-width-1-3">
<img src="https://docs.google.com/drawings/d/e/2PACX-1vSjsVZRBvz8AuNPcOOh7F8kyNkAHaK1FVcDXz6q9Mq3oQJSgjcEh9KPkh8PT7mHKGbrhQ0vFTQSXUxW/pub?w=812&h=554">
</div>
<div class="uk-width-1-3 status">
{{ $t(members["soracom_moto"]) }}
</div>
</div>
</div>
</div>
<div class="uk-section uk-padding-remove-vertical uk-section-primary">
<div clss="uk-container uk-container-expand">
<div uk-grid class="uk-grid-collapse">
<div class="uk-width-1-3">
<img src="https://docs.google.com/drawings/d/e/2PACX-1vRQ2ikHXaJuGzfvFOYowgJZBxROyq-xn1dK1iE1lwL3NaIwGqrVjxT7zmHHAQDoWUYmKsnZeVXyUWND/pub?w=812&h=554">
</div>
<div class="uk-width-1-3">
<img src="https://docs.google.com/drawings/d/e/2PACX-1vTiNqpkjiENsKyGJCSggJUsgoO-Fql-O0myJKu0vWZHC0nw_evQuzgHtKSO9JJLfnQb5WhFXfmKvedn/pub?w=812&h=554">
</div>
<div class="uk-width-1-3 status">
{{ $t(members["soracom_yaman"]) }}
</div>
</div>
</div>
</div>
</div><!-- #app1 -->
</body>
<script>
const i18n = new VueI18n({
locale: 'ja',
messages: {
ja: {
idle: '呼び出しOK!',
calling: '呼び出し中...',
running: '現場急行中!',
suspend: '―'
}
}
});
const app1 = new Vue({
el: '#app1',
i18n: i18n,
data: {
members: {}, // set defered
_target_things: null, // for iterator (not need reactive)
_lookup_key: null, // for lookup key in Shadow Document
_mqtt: null,
connectSettings: {
cognitoIdentityPoolId: '',
awsiotcoreEndpoint: '',
clientId: ''
}
},
methods: {
connect: function () {
AWS.config.region = this.connectSettings.cognitoIdentityPoolId.split(':')[0];
AWS.config.credentials = new AWS.CognitoIdentityCredentials({ IdentityPoolId: this.connectSettings.cognitoIdentityPoolId });
var self = this; /* ref: https://qiita.com/takeharu/items/9935ce476a17d6258e27 */
AWS.config.credentials.get(function () {
var endpoint = SigV4Utils.getSignedUrl(self.connectSettings.awsiotcoreEndpoint, AWS.config.region, AWS.config.credentials);
self._mqtt = new Paho.MQTT.Client(endpoint, self.connectSettings.clientId);
self._mqtt.connect({
useSSL: true,
mqttVersion: 4,
onSuccess: function () {
self._mqtt.subscribe('$aws/things/+/shadow/update/documents');
self._mqtt.subscribe('$aws/things/+/shadow/get/+', {
onSuccess: function () {
self._target_things.forEach(function (i) { // get current staet for bootup
self._mqtt.send(`$aws/things/${i}/shadow/get`, '{}');
});
}
});
},
onFailure: function (e) {
console.log(e);
}
});
self._mqtt.onConnectionLost = function (e) {
console.log(e);
};
self._mqtt.onMessageArrived = function (message) {
console.log(message.destinationName);
let topic = message.destinationName.split("/");
switch (topic.slice(-2).toString()) {
case ['update', 'documents'].toString():
var content = JSON.parse(message.payloadString).current;
break;
case ['get', 'accepted'].toString():
var content = JSON.parse(message.payloadString);
break;
case ['get', 'rejected'].toString():
console.warn(`Shadow not found: create > {"reported":{"status":"idle","welcome":null},"desired":{"${self._lookup_key}":null,"welcome":null}}`);
break;
default:
console.warn('Received other topic');
console.warn(message.payloadString);
return;
}
let thing_name = topic[2];
let status = content.state.reported[self._lookup_key]; // Need improved: In case of raising TypeError and in case of undefined
console.log(thing_name, status, content.version);
self.members[thing_name] = status;
};
});
}
}
});
window.onload = function () {
app1._target_things = ['soracom_max', 'soracom_moto', 'soracom_yaman'];
app1._lookup_key = "status";
app1.connectSettings.cognitoIdentityPoolId = `YOUR_AMAZON_COGNITO_POOL_ID`;
app1.connectSettings.awsiotcoreEndpoint = `YOUR_AWS_IOTCORE_CUSTOM_ENDPOINT`;
app1.connectSettings.clientId = `webclient0`;
app1._target_things.forEach(function(i) { // Dynamic setup using `_target_things`
app1.$set(app1.members, i, 'suspend');
});
app1.connect();
};
</script>
<!-- UIkit JS -->
<script src="//cdnjs.cloudflare.com/ajax/libs/uikit/3.0.3/js/uikit.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/uikit/3.0.3/js/uikit-icons.min.js"></script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment