Оповещение Google IOT на каждое устройство с помощью Stackdriver

Я хотел бы предупредить об отсутствии сердцебиения (или 0 полученных байтов) от любого из большого количества основных устройств Google IOT. Я не могу сделать это в Stackdriver. Вместо этого он, кажется, позволяет мне оповещать обо всем реестре устройств, который не дает мне то, что я ищу (Как я узнаю, что конкретное устройство отключено?)

Так как же это сделать?

1 ответ

Решение

Я понятия не имею, почему этот вопрос был назван слишком широким.

Правда в том, что у Google IOT нет предупреждений для каждого устройства, а вместо этого предлагается только предупреждение для всего реестра устройств. Если это не так, пожалуйста, ответьте на этот пост. Страница, которая ясно заявляет, что это здесь:

Cloud IoT Core экспортирует показатели использования, которые можно отслеживать программно или получить доступ через Stackdriver Monitoring. Эти показатели агрегируются на уровне реестра устройств. Вы можете использовать Stackdriver для создания панелей мониторинга или настройки оповещений.

Важность наличия предупреждений на устройство встроена в обещание, принятое в этом утверждении:

Оперативная информация о состоянии и функционировании устройств важна для обеспечения работоспособности и эффективности вашей системы сбора данных. Устройства могут быть расположены в жестких условиях или в труднодоступных местах. Мониторинг оперативной информации для ваших устройств IoT является ключом к сохранению потока данных, актуальных для бизнеса.

Поэтому сегодня нелегко получить предупреждение, если одно из множества глобально рассредоточенных устройств теряет связь. Нужно построить это, и в зависимости от того, что вы пытаетесь сделать, это повлечет за собой разные решения.

В моем случае я хотел предупредить, было ли время последнего тактового импульса или состояние последнего события старше 5 минут. Для этого мне нужно запустить функцию зацикливания, которая сканирует реестр устройства и регулярно выполняет эту операцию. Использование этого API описано в этом другом сообщении SO: статус основного соединения Google iot

Для справки, вот функция 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, ПОЛУЧИТЕ ЭТО ВМЕСТЕ!

Другие вопросы по тегам