В настоящее время к современным устройствам и гаджетам предъявляются довольно-таки высокие требования. И я говорю не только о серфинге в интернете, чтобы прочитать свою любимою новостную рассылку, проверить почту или пообщаться с друзьями в соц сети. Люди хотят гораздо большего, в современном мире просто необходимо управлять и мониторить устройства удаленно. Естественно управлять этими устройствами необходимо через Интернет. На данный момент существует огромное количество облачных решений, в данной статье рассмотрим облачное решение от компании Intel на практическом примере.

Для начала разберемся с новым облаком для Internet-of-Things.

Аналитическое облако IoT Analytics включает в себя ресурсы для сбора и анализа данных, собранных с различных сенсоров, подключенных к Intel Galileo и Intel Edison. Используя данный сервис, разработчик может с легкостью хранить и обрабатывать данные, не инвестируя в это дополнительные ресурсы, сосредоточась вместо этого на создании проектов под вышеупомянутые платы.
Рассмотрим концепцию использования IoT Analytics cloud.



Для того чтобы начать использовать облако IoT Analytics, необходимо создать админ-аккаунт, с помощью которого можно будет регистрировать девайсы, управлять оповещениями, создавать аккаунты и выполнять другие задачи на сайте. Перейти к использованию IoT Analytics Dashboard можно по ссылке. Базовые понятия и элементарные примеры использования данного облака описаны здесь.

Для того, чтобы продемонстрировать взаимодействие с облаком, продолжим работу над примером из статьи «Используем встроенный микроконтроллер в Intel Edison», в которой датчик измерения расстояния HC-SR04 подключается к плате Intel Edison и измеренное расстояние выводиться на LCD дисплей. Возьмем описанный пример измерения расстояния и добавим автоматическую загрузку полученных с датчика данных, прямиком в облако.



Сперва зарегистрируем наш датчик расстояния. Для этого заполним все необходимые поля.



Будем использовать целочисленный тип, зададим диапазон значений от -1 (ошибка) до 100 сантиметров.
Далее необходимо зарегистрировать датчик для Intel Edison. Используем следующую команду:
# iotkit-admin register dist distance.v1.0
# iotkit-admin catalog 

Теперь наш датчик зарегистрирован и закреплен за данным устройством.



Отправка данных в клауд может быть произведена посредством нескольких способов.
Один из самых простых:

# iotkit-admin observation dist 10 


Но, как вы понимаете, это не самый удобный способ отправлять данные в облако. Как правило, данная команда используется для тестирования.
Существует два других способа передачи данных в облако:
  • Настроить на клиенте интерфейс REST (Документация по настройке).
  • Отправление UDP пакетов агенту поднятому на плате. Агент конвертирует пакеты в REST вызовы и посылает запросы.

Для запуска агента на плате используем следующую команду:
# systemctl start iotkit-agent 

Существует возможность отправлять UDP сообщения через localhost на порт 41234 (UDP://localhost:41234). Чтобы это сделать, необходимо создать JSON-файл (JavaScript Object Notation):
{"n": "<sensor name>", "v": "<value>" } 

где “n” имя проводимого измерения, и “v” значение.
Например, так:
{ "n": "dist", "v": 17 }
{ "n": "dist", "v": 24} 

Я описал, каким образом отправлять данные в облако IoT Analytics через iotkit­agent. Разработчики также могут отправлять данные, используя такие языки программирования, как C/C++, JavaScript или Python. В одной из указанных в начале статей реализован пример публикации данных с помощью C/C++. Поскольку я предпочитаю концепцию более быстрого и удобного программирования, в данной статье я напишу небольшой пример используя мой любимый язык Python.

Скрипт IoTCloudManager.py:
import sys
import requests
import json
import uuid
import time
import random
import pyupm_i2clcd


host = "dashboard.us.enableiot.com"

proxies = {
    # Указываем проксю 
}

username = "email@gmail.com"
password = "*********"
account_name = "account_name"

# Указываем id девайса, если уже существует выдаст ошибку

device_id = "***************************************"

observations_per_hour = 1
days_of_data = 1

verify = True

api_root = "/v1/api"
base_url = "https://{0}{1}".format(host, api_root)
device_name = "Device-{0}".format(device_id)

g_user_token = ""
g_device_token = ""

def main():
    global g_user_token, g_device_token

    # инициализируем аутентификацию для последующих API вызовов
    g_user_token = get_token(username, password)

    # получаем user_id внутри Intel IoT Analytics Platform
    uid = get_user_id()
    print "UserId: {0}".format(uid)

    aid = get_account_id(uid, account_name)
    print "AccountId: {0}".format(aid)

    # создаем новый девайс с акаунтом
    create_device(aid, device_id, device_name)

    # Обновляем код активации
    ac = generate_activation_code(aid)
    print "Activation code: {0}".format(ac)

    # Активируем девайс
   g_device_token = activate(aid, device_id, ac)

    # Регистрируем сенсор измерения расстояния "Distance.v1.0". Данный вызов вернет component_id (cid) 
    cid = create_component(aid, device_id, "Distance.v1.0", "Dist")
    print "ComponentID (cid): {0}".format(cid)

    lcd = pyupm_i2clcd.Jhd1313m1(6, 0x3E, 0x62)
	with open('/dev/ttymcu0', 'w+t') as f:
		while True:
			f.write('get_distance\n') # Send command to MCU
			f.flush()
			line = f.readline() # Read response from MCU, -1 = ERROR
			value = int(line.strip('\n\r\t '))
                                                          # сабмитим данные в облако
		                   create_observations(aid, device_id, cid, value)
                                                          
			# читаем засабмиченные данные
   			o = get_observations(aid, device_id, cid)
    			print_observation_counts(o)

			lcd.clear()
			if value == -1:
				lcd.setColor(255, 0, 0) # RED
				lcd.write('ERROR')
			else:
				lcd.setColor(0, 255, 0) # GREEN
				lcd.write('%d cm' % (value,))
			time.sleep(1)
 
def get_user_headers():
    headers = {
        'Authorization': 'Bearer ' + g_user_token,
        'content-type': 'application/json'
    }
    return headers


def get_device_headers():
    headers = {
        'Authorization': 'Bearer ' + g_device_token,
        'content-type': 'application/json'
    }
    #print "Headers = " + str(headers) (ЗАКОМЕНЧЕННЫЙ КОД)
    return headers


def check(resp, code):
    if resp.status_code != code:
        print "Expected {0}. Got {1} {2}".format(code, resp.status_code, resp.text)
        sys.exit(1)

def get_token(username, password):
    url = "{0}/auth/token".format(base_url)
    headers = {'content-type': 'application/json'}
    payload = {"username": username, "password": password}
    data = json.dumps(payload)
    resp = requests.post(url, data=data, headers=headers, proxies=proxies, verify=verify)
    check(resp, 200)
    js = resp.json()
    token = js['token']
    return token

def get_user_id():
    url = "{0}/auth/tokenInfo".format(base_url)
    resp = requests.get(url, headers=get_user_headers(), proxies=proxies, verify=verify)
    check(resp, 200)
    js = resp.json()
    user_id = js["payload"]["sub"]
    return user_id

def get_account_id(user_id, account_name):
    url = "{0}/users/{1}".format(base_url, user_id)
    resp = requests.get(url, headers=get_user_headers(), proxies=proxies, verify=verify)
    check(resp, 200)
    js = resp.json()
    if 'accounts' in js:
        accounts = js["accounts"]
        for k, v in accounts.iteritems():
            if 'name' in v and v["name"] == account_name:
                return k
    print "Account name {0} not found.".format(account_name)
    print "Available accounts are: {0}".format([v["name"] for k, v in accounts.iteritems()])
    return None

def create_device(account, device_id, device_name):
    url = "{0}/accounts/{1}/devices".format(base_url, account)
    device = {
        "deviceId": str(device_id),
        "gatewayId": str(device_id),
        "name": device_name,
        "tags": ["Russia", "Moscow", "RoadShow"],
        "attributes": {
            "vendor": "intel",
            "platform": "x86",
            "os": "linux"
        }
    }
    data = json.dumps(device)
    resp = requests.post(url, data=data, headers=get_user_headers(), proxies=proxies, verify=verify)
    check(resp, 201)
    return resp

def generate_activation_code(account_id):
    url = "{0}/accounts/{1}/activationcode/refresh".format(base_url, account_id)
    resp = requests.put(url, headers=get_user_headers(), proxies=proxies, verify=verify)
    check(resp, 200)
    js = resp.json()
    activation_code = js["activationCode"]
    return activation_code

def activate(account_id, device_id, activation_code):
    url = "{0}/accounts/{1}/devices/{2}/activation".format(base_url, account_id, device_id)
    activation = {
        "activationCode": activation_code
    }
    data = json.dumps(activation)
    resp = requests.put(url, data=data, headers=get_user_headers(), proxies=proxies, verify=verify)
    check(resp, 200)
    js = resp.json()
    if "deviceToken" in js:
        token = js["deviceToken"]
        return token
    else:
        print js
        sys.exit(1)

def create_component(account_id, device_id, component_type_name, name):
    url = "{0}/accounts/{1}/devices/{2}/components".format(base_url, account_id, device_id)
    component = {
        "type": component_type_name,
        "name": name,
        "cid": str(uuid.uuid4())
    }
    data = json.dumps(component)
    resp = requests.post(url, data=data, headers=get_device_headers(), proxies=proxies, verify=verify)
    check(resp, 201)
    js = resp.json()
    return js["cid"]

def create_observations(account_id, device_id, cid, val):
    url = "{0}/data/{1}".format(base_url, device_id)
    body = {
        "accountId": account_id,
        "data": []
    }
        o = {
            "componentId": cid,
            "value": str(val),
            "attributes": {
                "i": i
            }
        }
        body["data"].append(o)
    data = json.dumps(body)
    resp = requests.post(url, data=data, headers=get_device_headers(), proxies=proxies, verify=verify)
    check(resp, 201)

def get_observations(account_id, device_id, component_id):
    url = "{0}/accounts/{1}/data/search".format(base_url, account_id)
    search = {
        "from": 0,
        "targetFilter": {
            "deviceList": [device_id]
        },
        "metrics": [
            {
                "id": component_id
            }
        ]
    }
    data = json.dumps(search)
    resp = requests.post(url, data=data, headers=get_user_headers(), proxies=proxies, verify=verify)
    check(resp, 200)
    js = resp.json()
    return js

def print_observation_counts(js): 
    if 'series' in js:
        series = js["series"]
        series = sorted(series, key=lambda v: v["deviceName"])
        for v in series:
            print "Device: {0} Count: {1}".format(v["deviceName"], len(v["points"]))

if __name__ == "__main__":
    main()



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

Таким образом, достаточно легко загружать данные в облако.
Теперь попробуем определить максимальное и минимальное расстояние дистанции (см), которые мы отправили в облако. Получаем следующую картину.

В качестве заключения хочется отметить, что облако IoT Analytics является простым и удобным инструментом для хранения и анализа данных, получаемых с подключенных к платам датчиков.

Комментарии (4)


  1. nckma
    17.07.2015 09:36
    -1

    Кажется жизнь будет становиться все опасней и опасней.
    Сперва хранение данных от датчиков умного дома в облаке. Потом удаленное управление домашней техникой… Утечки паролей, перехват управления домашним оборудованием хакерами: кондиционеры, газовые колонки, телевизоры и гаражная автоматика…
    Ну или просто — едешь домой дистанционно включил чайник. Застрял в пробке, вода в чайнике выкипела, пожар. Оказывается в фирмваре чайника было необрабатываемое исключение, которое не обнаружили тестировщики…


    1. Klukonin
      17.07.2015 14:57
      +3

      Странно что человека минусуют.
      Почему-то люди считают что, например, вирусы-локеры для персональных компьютеров не применимы к умной бытовой технике. Хотя, любая техника с интерфейсом в один прекрасный день может выдать сообщение о том что ваша стиралка/сушилка/микроволновка/холодильник подверглась блокировке и просит отправить смс на номер. Стоимость вызова мастера для перепрошивки будет, предположим, в два раза выше стоимости смс. Вполне реальный сценарий.
      Логично что чем больше уровень информатизации и чем больше потенциально уязвимых узлов — тем больше рисков с этим связанных.
      Риски эти нужно учитывать. При этом, выносить за скобки атаки на технику с целью нанести ущерб, по меньшей мере, глупо. И аргументы «кому я/ты/Вася нужен» не канают. Массовый вывод из строя котельных в городе или районе, допустим, зимой в -30 — прекрасный сценарий для террористической атаки.


  1. 4robots
    17.07.2015 15:33
    +2

    Спасибо. В данном примере считали расстояние сохранили в облаке. Посмотрели график. Красиво.
    Есть идеи про Аналитику? Ведь облако IoT Analitycs или это просто для красоты названия?


  1. crea7or
    18.07.2015 00:30

    Не понимаю, в чём такая необходимость Эдисона? Он же стоит с платой больше $100. Ну вот, например, Particle Io — ARM+WIFI в размере Arduino nano: $19. Использовать очень просто. Там же можно и сотовой сетью: $39-$49. Своё облако они тоже предоставляют. Да и Azure не сложно подрубить. Или вот Node McuLua за $7 тоже с WIFI (вот тут примерно как их использовать). С ним, конечно, всё сами.