使用Stackdriver的每个设备心跳警报的Google IOT

时间:2018-03-16 21:28:44

标签: google-cloud-platform stackdriver google-cloud-iot

我想提醒大量Google IOT核心设备中没有心跳(或收到0个字节)。我似乎无法在Stackdriver中执行此操作。它似乎让我在整个设备注册表上发出警报,这不会给我我正在寻找的内容(我怎么知道特定设备已断开连接?)

那么如何做到这一点?

2 个答案:

答案 0 :(得分:3)

我不知道为什么这个问题被视为“过于宽泛”。

事实是Google IOT没有每个设备提醒,而是仅提供整个设备注册表的警报。如果不是这样,请回复此帖。清楚说明此is here的页面:

  

Cloud IoT Core导出可以监控的使用率指标   以编程方式或通过Stackdriver Monitoring访问。这些指标   在设备注册表级别聚合。你可以使用Stackdriver   创建仪表板或设置警报。

每个设备提醒的重要性已纳入this statement中承诺的承诺:

  

有关设备运行状况和功能的运营信息是   确保您的数据收集结构健康,这一点非常重要   表现良好。设备可能位于恶劣环境或中   难以进入的地点。监控您的运营情报   物联网设备是保留业务相关数据流的关键。

因此,如果许多全球分散的设备中的一个失去连接,那么今天就不容易获得警报。人们需要建立这一点,并且取决于人们想要做什么,这将需要不同的解决方案。

在我的情况下,我想提醒最后一次心跳时间或最后一次事件状态发布是否超过5分钟。为此,我需要运行一个循环函数来扫描设备注册表并定期执行此操作。此API的使用概述于此其他SO帖子:Google iot core connection status

答案 1 :(得分:0)

作为参考,这是我刚编写的Firebase函数,用于检查设备的在线状态,可能需要进行一些调整和进一步的测试,但要以任何帮助从其他任何人入手:

// Example code to call this function
// const checkDeviceOnline = functions.httpsCallable('checkDeviceOnline');
// Include 'current' key for 'current' online status to force update on db with delta
// const isOnline = await checkDeviceOnline({ deviceID: 'XXXX', current: true })
export const checkDeviceOnline = functions.https.onCall(async (data, context) => {

    if (!context.auth) {
        throw new functions.https.HttpsError('failed-precondition', 'You must be logged in to call this function!');
    }

    // deviceID is passed in deviceID object key
    const deviceID = data.deviceID

    const dbUpdate = (isOnline) => {
        if (('wasOnline' in data) && data.wasOnline !== isOnline) {
            db.collection("devices").doc(deviceID).update({ online: isOnline })
        }

        return isOnline
    }

    const deviceLastSeen = () => {
        // We only want to use these to determine "latest seen timestamp"
        const stamps = ["lastHeartbeatTime", "lastEventTime", "lastStateTime", "lastConfigAckTime", "deviceAckTime"]
        return stamps.map(key => moment(data[key], "YYYY-MM-DDTHH:mm:ssZ").unix()).filter(epoch => !isNaN(epoch) && epoch > 0).sort().reverse().shift()
    }

    await dm.setAuth()

    const iotDevice: any = await dm.getDevice(deviceID)

    if (!iotDevice) {
        throw new functions.https.HttpsError('failed-get-device', 'Failed to get device!');
    }

    console.log('iotDevice', iotDevice)

    // If there is no error status and there is last heartbeat time, assume device is online
    if (!iotDevice.lastErrorStatus && iotDevice.lastHeartbeatTime) {
        return dbUpdate(true)
    }

    // Add iotDevice.config.deviceAckTime to root of object
    // For some reason in all my tests, I NEVER receive anything on lastConfigAckTime, so this is my workaround
    if (iotDevice.config && iotDevice.config.deviceAckTime) iotDevice.deviceAckTime = iotDevice.config.deviceAckTime

    // If there is a last error status, let's make sure it's not a stale (old) one
    const lastSeenEpoch = deviceLastSeen()
    const errorEpoch = iotDevice.lastErrorTime ? moment(iotDevice.lastErrorTime, "YYYY-MM-DDTHH:mm:ssZ").unix() : false

    console.log('lastSeen:', lastSeenEpoch, 'errorEpoch:', errorEpoch)

    // Device should be online, the error timestamp is older than latest timestamp for heartbeat, state, etc
    if (lastSeenEpoch && errorEpoch && (lastSeenEpoch > errorEpoch)) {
        return dbUpdate(true)
    }

    // error status code 4 matches
    // lastErrorStatus.code = 4
    // lastErrorStatus.message = mqtt: SERVER: The connection was closed because MQTT keep-alive check failed.
    // will also be 4 for other mqtt errors like command not sent (qos 1 not acknowledged, etc)
    if (iotDevice.lastErrorStatus && iotDevice.lastErrorStatus.code && iotDevice.lastErrorStatus.code === 4) {
        return dbUpdate(false)
    }

    return dbUpdate(false)
})

我还创建了一个与命令一起使用的函数,用于将命令发送到设备以检查其是否在线:

export const isDeviceOnline = functions.https.onCall(async (data, context) => {

    if (!context.auth) {
        throw new functions.https.HttpsError('failed-precondition', 'You must be logged in to call this function!');
    }

    // deviceID is passed in deviceID object key
    const deviceID = data.deviceID

    await dm.setAuth()

    const dbUpdate = (isOnline) => {
        if (('wasOnline' in data) && data.wasOnline !== isOnline) {
            console.log( 'updating db', deviceID, isOnline )
            db.collection("devices").doc(deviceID).update({ online: isOnline })
        } else {
            console.log('NOT updating db', deviceID, isOnline)
        }

        return isOnline
    }

    try {
        await dm.sendCommand(deviceID, 'alive?', 'alive')
        console.log('Assuming device is online after succesful alive? command')
        return dbUpdate(true)
    } catch (error) {
        console.log("Unable to send alive? command", error)
        return dbUpdate(false)
    }
})

这也使用了我修改后的DeviceManager版本,您可以在该要点上找到所有示例代码(以确保使用最新更新,并在此处保持较小的位置): https://gist.github.com/tripflex/3eff9c425f8b0c037c40f5744e46c319

所有这些代码,仅用于检查设备是否在线……这可以由Google发出某种事件或添加一种简便的方法来轻松处理。 一起上Google吧!