diff --git a/IoTCIntegration/index.js b/IoTCIntegration/index.js index 426ae92..c7697ad 100644 --- a/IoTCIntegration/index.js +++ b/IoTCIntegration/index.js @@ -18,7 +18,7 @@ let kvToken; module.exports = async function (context, req) { try { - await handleMessage({ ...parameters, log: context.log, getSecret: getKeyVaultSecret }, req.body.device, req.body.measurements); + await handleMessage({ ...parameters, log: context.log, getSecret: getKeyVaultSecret }, req.body.device, req.body.measurements, req.body.timestamp); } catch (e) { context.log('[ERROR]', e.message); diff --git a/IoTCIntegration/lib/engine.js b/IoTCIntegration/lib/engine.js index 37ff64e..489ff65 100644 --- a/IoTCIntegration/lib/engine.js +++ b/IoTCIntegration/lib/engine.js @@ -26,7 +26,7 @@ const deviceCache = {}; * @param {{ deviceId: string }} device * @param {{ [field: string]: number }} measurements */ -module.exports = async function (context, device, measurements) { +module.exports = async function (context, device, measurements, timestamp) { if (device) { if (!device.deviceId || !/^[a-z0-9\-]+$/.test(device.deviceId)) { throw new StatusError('Invalid format: deviceId must be alphanumeric, lowercase, and may contain hyphens.', 400); @@ -39,12 +39,22 @@ module.exports = async function (context, device, measurements) { throw new StatusError('Invalid format: invalid measurement list.', 400); } + if (timestamp && isNaN(Date.parse(timestamp))) { + throw new StatusError('Invalid format: if present, timestamp must be in ISO format (e.g., YYYY-MM-DDTHH:mm:ss.sssZ)', 400); + } + const client = Device.Client.fromConnectionString(await getDeviceConnectionString(context, device), DeviceTransport.Http); try { + const message = new Device.Message(JSON.stringify(measurements)); + + if (timestamp) { + message.properties.add('iothub-creation-time-utc', timestamp); + } + await util.promisify(client.open.bind(client))(); context.log('[HTTP] Sending telemetry for device', device.deviceId); - await util.promisify(client.sendEvent.bind(client))(new Device.Message(JSON.stringify(measurements))); + await util.promisify(client.sendEvent.bind(client))(message); await util.promisify(client.close.bind(client))(); } catch (e) { // If the device was deleted, we remove its cached connection string diff --git a/README.md b/README.md index fe03c74..7692e1a 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ In the console, run the command `npm install` (this command takes ~20 minutes to ![Get function URL](assets/getFunctionUrl.PNG "Get function URL") -Messages sent to the device bridge must have the following format in the Body: +Messages sent to the device bridge must have the following format in the body: ```json { "device": { @@ -49,6 +49,10 @@ Messages sent to the device bridge must have the following format in the Body: } ``` +An optional `timestamp` field can be included in the body, to specify the UTC date and time of the message. +This field must be in ISO format (e.g., YYYY-MM-DDTHH:mm:ss.sssZ). If `timestamp` is not provided, +the current date and time will be used. + > NOTE: `deviceId` must be alphanumeric, lowercase, and may contain hyphens. The values of the fields in `measurements` must be numbers or strings. 6. When a message with a new `deviceId` is sent to IoT Central by the device bridge, a device will be created as an **Unassociated device**. Unassociated devices appear in your IoT Central application in `Device Explorer > Unassociated devices`. Click `Associate` and choose a device template to start receiving incoming measurements from that device in IoT Central. @@ -246,7 +250,7 @@ Function. You can check the integrity of the code being deployed by verifying th of the `iotc-bridge-az-function.zip` file in the root of this repository matches the following: ``` -A55889E1808D666CE03A2A32C2B304F4DADAA6F72D599CA0D4A15C8666737E4F +4DE7C133828461E5C2E11125E7B22E12AA4E238BF19F4837E0D16950109DAF68 ``` # Contributing diff --git a/iotc-bridge-az-function.zip b/iotc-bridge-az-function.zip index 121dbe5..fe8ad59 100644 Binary files a/iotc-bridge-az-function.zip and b/iotc-bridge-az-function.zip differ