Add command for updating Module Twin (#97)

* Add command for updating Module Twin

* Better naming

* Resolve comments
This commit is contained in:
Jun Han 2018-06-11 13:37:09 +08:00 коммит произвёл GitHub
Родитель d49ec7f47c
Коммит 7ddf5eaf55
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 121 добавлений и 28 удалений

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

@ -21,10 +21,10 @@ Interact with Azure IoT Hub, IoT Device Management, IoT Edge Management, IoT Hub
* Send C2D message to device
* Monitor C2D message from IoT Hub
* Invoke Direct Method
* Get/update Device Twin
* Edit Device Twin
* Interact with Azure IoT Edge <sup>Preview</sup> (Install [Azure IoT Edge](https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.azure-iot-edge) for more IoT Edge support)
* List Edge Moudles
* View Module Twin
* Edit Module Twin
* Manage Edge runtime
* Create deployment for Edge device
* Generate Edge setup configuration file

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

@ -59,7 +59,9 @@
"onCommand:azure-iot-toolkit.uninstallEdge",
"onCommand:azure-iot-toolkit.loginToContainerRegistry",
"onCommand:azure-iot-toolkit.generateEdgeSetupConfig",
"onCommand:azure-iot-toolkit.createIoTHub"
"onCommand:azure-iot-toolkit.createIoTHub",
"onCommand:azure-iot-toolkit.getModuleTwin",
"onCommand:azure-iot-toolkit.updateModuleTwin"
],
"main": "./out/src/extension",
"contributes": {
@ -129,7 +131,7 @@
},
{
"command": "azure-iot-toolkit.getDeviceTwin",
"title": "Get Device Twin",
"title": "Edit Device Twin",
"category": "Azure IoT Hub"
},
{
@ -223,7 +225,12 @@
},
{
"command": "azure-iot-toolkit.getModuleTwin",
"title": "Get Module Twin",
"title": "Edit Module Twin",
"category": "Azure IoT Edge"
},
{
"command": "azure-iot-toolkit.updateModuleTwin",
"title": "Update Module Twin",
"category": "Azure IoT Edge"
}
],
@ -401,6 +408,11 @@
"when": "resourceFilename == azure-iot-device-twin.json",
"command": "azure-iot-toolkit.updateDeviceTwin",
"group": "navigation"
},
{
"when": "resourceFilename == azure-iot-module-twin.json",
"command": "azure-iot-toolkit.updateModuleTwin",
"group": "navigation"
}
],
"explorer/context": [

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

@ -145,6 +145,10 @@ export class AzureIoTExplorer {
}
public async getModuleTwin(moduleItem: ModuleItem) {
this._iotEdgeExplorer.getModuleTwin(moduleItem);
await this._iotEdgeExplorer.getModuleTwin(moduleItem);
}
public async updateModuleTwin() {
await this._iotEdgeExplorer.updateModuleTwin();
}
}

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

@ -2,6 +2,9 @@
// Licensed under the MIT license.
"user strict";
import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";
export class Constants {
public static ExtensionId = "vsciot-vscode.azure-iot-toolkit";
@ -21,6 +24,7 @@ export class Constants {
public static IoTHubDirectMethodLabel = "DirectMethod";
public static IoTHubDeviceTwinLabel = "DeviceTwin";
public static IoTHubModuleTwinLabel = "ModuleTwin";
public static IoTHubAILoadDeviceTreeEvent = "AZ.LoadDeviceTree";
public static IoTHubAIStartMonitorEvent = "AZ.D2C.startMonitoring";
@ -35,12 +39,18 @@ export class Constants {
public static IoTHubAIGetDeviceTwinStartEvent = "AZ.DeviceTwin.Get.Start";
public static IoTHubAIGetDeviceTwinDoneEvent = "AZ.DeviceTwin.Get.Done";
public static IoTHubAIUpdateDeviceTwinEvent = "AZ.DeviceTwin.Update";
public static DeviceTwinJosnFileName = "azure-iot-device-twin.json";
public static DeviceTwinJosnFilePath: string;
public static IoTHubAIEdgeDeployStartEvent = "Edge.Deploy.Start";
public static IoTHubAIEdgeDeployDoneEvent = "AZ.Edge.Deploy.Done";
public static IoTHubAICreateStartEvent = "General.IoTHub.Create.Start";
public static IoTHubAICreateDoneEvent = "AZ.IoTHub.Create.Done";
public static IoTHubAIGetModuleTwinStartEvent = "AZ.Edge.ModuleTwin.Get.Start";
public static IoTHubAIGetModuleTwinDoneEvent = "AZ.Edge.ModuleTwin.Get.Done";
public static IoTHubAIUpdateModuleTwinStartEvent = "AZ.Edge.ModuleTwin.Update.Start";
public static IoTHubAIUpdateModuleTwinDoneEvent = "AZ.Edge.ModuleTwin.Update.Done";
public static ModuleTwinJosnFileName = "azure-iot-module-twin.json";
public static ModuleTwinJosnFilePath: string;
public static IoTHubAILoadModuleTreeStartEvent = "AZ.Edge.LoadModuleTree.Start";
public static IoTHubAILoadModuleTreeDoneEvent = "AZ.Edge.LoadModuleTree.Done";
@ -59,4 +69,12 @@ export class Constants {
public static ShowIoTHubInfoKey = "showIoTHubInfo";
public static ShowConnectionStringInputBoxKey = "showConnectionStringInputBox";
public static IoTHubApiVersion = "2017-11-08-preview";
public static initialize(context: vscode.ExtensionContext) {
const directory = context.storagePath ? context.storagePath : os.tmpdir();
Constants.ModuleTwinJosnFilePath = path.join(directory, Constants.ModuleTwinJosnFileName);
Constants.DeviceTwinJosnFilePath = path.join(directory, Constants.DeviceTwinJosnFileName);
}
private static a;
}

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

@ -4,6 +4,7 @@
"use strict";
import * as vscode from "vscode";
import { AzureIoTExplorer } from "./azureIoTExplorer";
import { Constants } from "./constants";
import { DeviceTree } from "./deviceTree";
import { Executor } from "./executor";
import { TelemetryClient } from "./telemetryClient";
@ -11,6 +12,7 @@ import { TelemetryClient } from "./telemetryClient";
export function activate(context: vscode.ExtensionContext) {
TelemetryClient.sendEvent("extensionActivated");
Constants.initialize(context);
let azureIoTExplorer = new AzureIoTExplorer(context);
let deviceTree = new DeviceTree(context);
@ -136,6 +138,10 @@ export function activate(context: vscode.ExtensionContext) {
await azureIoTExplorer.getModuleTwin(moduleItem);
}));
context.subscriptions.push(vscode.commands.registerCommand("azure-iot-toolkit.updateModuleTwin", async () => {
await azureIoTExplorer.updateModuleTwin();
}));
vscode.workspace.onDidChangeTextDocument((event) => azureIoTExplorer.replaceConnectionString(event));
context.subscriptions.push(vscode.window.onDidCloseTerminal((closedTerminal: vscode.Terminal) => {

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

@ -166,6 +166,37 @@ export class IoTEdgeExplorer extends BaseExplorer {
}
public async getModuleTwin(moduleItem: ModuleItem) {
if (moduleItem) {
await this.getModuleTwinById(moduleItem.deviceId, moduleItem.moduleId);
}
}
public async updateModuleTwin() {
TelemetryClient.sendEvent(Constants.IoTHubAIUpdateModuleTwinStartEvent);
const iotHubConnectionString = await Utility.getConnectionString(Constants.IotHubConnectionStringKey, Constants.IotHubConnectionStringTitle);
if (!iotHubConnectionString) {
return;
}
try {
const moduleTwinContent = await Utility.readFromActiveFile(Constants.ModuleTwinJosnFileName);
if (!moduleTwinContent) {
return;
}
const moduleTwinJson = JSON.parse(moduleTwinContent);
this._outputChannel.show();
this.outputLine(Constants.IoTHubModuleTwinLabel, `Update Module Twin for [${moduleTwinJson.deviceId}][${moduleTwinJson.moduleId}]...`);
await Utility.updateModuleTwin(iotHubConnectionString, moduleTwinJson.deviceId, moduleTwinJson.moduleId, moduleTwinContent);
this.outputLine(Constants.IoTHubModuleTwinLabel, `Module Twin updated successfully`);
TelemetryClient.sendEvent(Constants.IoTHubAIUpdateModuleTwinDoneEvent, { Result: "Success" });
await this.getModuleTwinById(moduleTwinJson.deviceId, moduleTwinJson.moduleId);
} catch (error) {
this.outputLine(Constants.IoTHubModuleTwinLabel, `Failed to update Module Twin: ${error}`);
TelemetryClient.sendEvent(Constants.IoTHubAIUpdateModuleTwinDoneEvent, { Result: "Fail", Message: error });
}
}
private async getModuleTwinById(deviceId: string, moduleId: string) {
TelemetryClient.sendEvent(Constants.IoTHubAIGetModuleTwinStartEvent);
const iotHubConnectionString = await Utility.getConnectionString(Constants.IotHubConnectionStringKey, Constants.IotHubConnectionStringTitle);
if (!iotHubConnectionString) {
@ -173,12 +204,16 @@ export class IoTEdgeExplorer extends BaseExplorer {
}
try {
const content = await Utility.getModuleTwin(iotHubConnectionString, moduleItem.deviceId, moduleItem.moduleId);
const textDocument = await vscode.workspace.openTextDocument({ content: JSON.stringify(content, null, 4), language: "json" });
vscode.window.showTextDocument(textDocument);
TelemetryClient.sendEvent(Constants.IoTHubAIGetModuleTwinDoneEvent, { Result: "Success"});
const twin = await Utility.getModuleTwin(iotHubConnectionString, deviceId, moduleId);
Utility.writeJson(Constants.ModuleTwinJosnFilePath, twin);
const document = await vscode.workspace.openTextDocument(Constants.ModuleTwinJosnFilePath);
if (document.isDirty) {
throw new Error(`Your ${Constants.ModuleTwinJosnFileName} has unsaved changes. Please close or save the file. Then try again.`);
}
vscode.window.showTextDocument(document);
TelemetryClient.sendEvent(Constants.IoTHubAIGetModuleTwinDoneEvent, { Result: "Success" });
} catch (error) {
vscode.window.showErrorMessage(`Failed to get Module Twin: ${error}`);
this.outputLine(Constants.IoTHubModuleTwinLabel, `Failed to get Module Twin: ${error}`);
TelemetryClient.sendEvent(Constants.IoTHubAIGetModuleTwinDoneEvent, { Result: "Fail", Message: error });
}
}

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

@ -13,9 +13,6 @@ import { DeviceItem } from "./Model/DeviceItem";
import { TelemetryClient } from "./telemetryClient";
import { Utility } from "./utility";
const deviceTwinJosnFileName = "azure-iot-device-twin.json";
const deviceTwinJosnFilePath = path.join(os.tmpdir(), deviceTwinJosnFileName);
export class IotHubDeviceTwinExplorer extends BaseExplorer {
constructor(outputChannel: vscode.OutputChannel) {
super(outputChannel);
@ -44,10 +41,10 @@ export class IotHubDeviceTwinExplorer extends BaseExplorer {
this.outputLine(Constants.IoTHubDeviceTwinLabel, `Failed to get Device Twin: ${err.message}`);
} else {
this.outputLine(Constants.IoTHubDeviceTwinLabel, `Device Twin retrieved successfully`);
fs.writeFileSync(deviceTwinJosnFilePath, `${JSON.stringify(twin, null, 4)}`);
vscode.workspace.openTextDocument(deviceTwinJosnFilePath).then((document: vscode.TextDocument) => {
Utility.writeJson(Constants.DeviceTwinJosnFilePath, twin);
vscode.workspace.openTextDocument(Constants.DeviceTwinJosnFilePath).then((document: vscode.TextDocument) => {
if (document.isDirty) {
vscode.window.showWarningMessage(`Your ${deviceTwinJosnFileName} has unsaved changes. \
vscode.window.showWarningMessage(`Your ${Constants.DeviceTwinJosnFileName} has unsaved changes. \
Please close or save the file. Then try again.`);
}
vscode.window.showTextDocument(document);
@ -57,24 +54,19 @@ export class IotHubDeviceTwinExplorer extends BaseExplorer {
}
public async updateDeviceTwin() {
TelemetryClient.sendEvent(Constants.IoTHubAIUpdateDeviceTwinEvent);
let iotHubConnectionString = await Utility.getConnectionString(Constants.IotHubConnectionStringKey, Constants.IotHubConnectionStringTitle);
if (!iotHubConnectionString) {
return;
}
TelemetryClient.sendEvent(Constants.IoTHubAIUpdateDeviceTwinEvent);
const activeTextEditor = vscode.window.activeTextEditor;
if (!activeTextEditor || !activeTextEditor.document || !activeTextEditor.document.fileName.endsWith(deviceTwinJosnFileName)) {
vscode.window.showWarningMessage(`Please open ${deviceTwinJosnFileName} and try again.`);
return;
}
try {
this._outputChannel.show();
let document = activeTextEditor.document;
await document.save();
let deviceTwinContent = activeTextEditor.document.getText();
let deviceTwinContent = await Utility.readFromActiveFile(Constants.DeviceTwinJosnFileName);
if (!deviceTwinContent) {
return;
}
let deviceTwinJson = JSON.parse(deviceTwinContent);
this._outputChannel.show();
this.outputLine(Constants.IoTHubDeviceTwinLabel, `Update Device Twin for [${deviceTwinJson.deviceId}]...`);
let registry = iothub.Registry.fromConnectionString(iotHubConnectionString);
registry.updateTwin(deviceTwinJson.deviceId, deviceTwinContent, deviceTwinJson.etag, (err) => {

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

@ -198,6 +198,32 @@ export class Utility {
return (await axios.request(config)).data;
}
public static async updateModuleTwin(iotHubConnectionString: string, deviceId: string, moduleId: string, twin: any): Promise<string> {
const url = `/twins/${encodeURIComponent(deviceId)}/modules/${moduleId}?api-version=${Constants.IoTHubApiVersion}`;
const config = Utility.generateIoTHubAxiosRequestConfig(iotHubConnectionString, url, "put", twin);
return (await axios.request(config)).data;
}
public static async readFromActiveFile(fileName: string): Promise<string> {
const activeTextEditor = vscode.window.activeTextEditor;
if (!activeTextEditor || !activeTextEditor.document || path.basename(activeTextEditor.document.fileName) !== fileName) {
vscode.window.showWarningMessage(`Please open ${fileName} and try again.`);
return "";
}
const document = activeTextEditor.document;
await document.save();
return document.getText();
}
public static writeJson(filePath: string, data) {
const directory = path.dirname(filePath);
if (!fs.existsSync(directory)) {
fs.mkdirSync(directory);
}
fs.writeFileSync(filePath, `${JSON.stringify(data, null, 4)}`);
}
public static async getInputDevice(deviceItem: DeviceItem, eventName: string, onlyEdgeDevice: boolean = false, iotHubConnectionString?: string): Promise<DeviceItem> {
if (!deviceItem) {
if (eventName) {