Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Создание IR-моста для SmartThings на Arduino UNO и ThingShield

Компоненты и материалы

Компонент Количество
Arduino UNO 1
SmartThings Shield для Arduino (ThingShield) 1
IR-светодиод (излучатель) 1
IR-приемник (фотодиод) 1
Резистор 100 Ом (опционально) 1

О проекте

Введение

Обычный пульт от телевизора способен на гораздо большее, чем просто переключение каналов, когда подключен к облаку SmartThings. С минимальным набором деталей и быстрым результатом этот проект — отличный способ изучить платформу.

Основы Arduino и ThingShield

SmartThings ThingShield упрощает создание прототипов для SmartThings на базе Arduino. Шилд подключается напрямую к UNO, связываясь с хабом SmartThings по протоколу Zigbee. Переключатель на шилде позволяет выбрать использование пинов 0,1 или 2,3 для связи с Arduino. ThingShield уже резервирует пин 6.

Подробнее о начале работы с Arduino: arduino.cc

Шаг 1: Необходимые детали

Шаг 2: Установка IR-библиотеки

Проект использует библиотеку Arduino от Кена Ширрифа: GitHub

Установите библиотеку стандартным способом: руководство

После установки нужно изменить IRRemoteInt.h для использования таймера на пине 9. В этом примере пин 3 используется для связи с ThingShield.

Шаг 3: Скетч Arduino

Загрузите скетч в Arduino (см. раздел Код).

Шаг 4: Сборка

Сборка простая. Сначала установите ThingShield на Arduino. На схеме ниже показан только Arduino, но расположение пинов одинаковое с установленным шилдом.

IR-приемник: соедините соответствующие пины с GND и 5V. Вывод данных — на пин 11 Arduino.

IR-светодиод: анод на пин 9, катод на GND. Резистор 100 Ом опционален — светодиод выдерживает пиковый ток Arduino при быстрой модуляции. При постоянном токе он бы сгорел.

Шаг 5: Создание кастомного Device Type в SmartThings

В SmartThings IDE создайте новый Device Type для ThingShield.

  1. Перейдите в «My Device Types», нажмите «New SmartDevice» справа.
  2. Дайте имя: «Ir Bridge» (будем ссылаться на это имя в SmartApp).
  3. Определите Attributes (переменные) и Commands (функции). Для урока создадим атрибуты и команды для двух программируемых кнопок и кнопки записи. Добавьте показанные атрибуты и команды. Нажмите «Create» для перехода к кодированию устройства.
  4. Скопируйте определение устройства в окно кода IDE (см. раздел Код). Нажмите «Save», затем «Publish» для доступности устройства.

Шаг 6: Обновление ThingShield до нового Device Type

Добавьте ThingShield к хабу SmartThings, если еще не сделано. Для сопряжения: установите ThingShield на Arduino, подайте питание. Удерживайте кнопку «Switch» на шилде 6 секунд. В приложении SmartThings нажмите Add. Нажмите физическую кнопку «switch» еще раз — хаб должен обнаружить ThingShield.

В IDE перейдите к вашему Arduino ThingShield: «devices» на главном экране. Выберите устройство, нажмите «Edit». В выпадающем меню «Type» выберите созданный SmartDevice type. Дайте понятное имя (Label). Нажмите Update.

Примечание: при будущих обновлениях кастомных Device Types вернитесь сюда, чтобы убедиться, что физические устройства остались связанными с правильным типом после публикации обновления.

Шаг 7: Написание SmartApp

Последний кусок кода — сам SmartApp. Перейдите в «My SmartApps», начните «New SmartApp» кнопкой справа. Дайте имя, описание, категорию («My apps»). Нажмите «Create» для кодирования.

Скопируйте код SmartApp (см. раздел Код). Нажмите «Save», затем «Publish» для доступности в iOS/Android приложении SmartThings.

Обратите внимание: мы ссылаемся на SmartDevice type по имени «IrBridge» без пробела, который был в «Ir Bridge»:

input "irDevice", "device.IrBridge"

Строка позволяет показывать только устройства типа «Ir Bridge» для выбора в SmartApp. CamelCasing специфичен: при ссылке на device types в smart apps пробелы удаляются, первый символ и символы после пробелов становятся заглавными, остальные — строчные.

Шаг 8: Активация SmartApp

В приложении SmartThings на смартфоне свяжите новый SmartApp с нашим IR-устройством и выберите коммутаторы для управления. Нажмите «install».

Для программирования кнопок в приложении: зайдите в детали тайла (шестеренка в углу). Нажмите большую кнопку записи — она станет красной (режим записи). Нажмите тайл (Play/Pause или B), которым хотите управлять — он станет желтым. Наведите пульт на ThingShield и нажмите кнопку для обучения. ThingShield отправит код в облако SmartThings и свяжет его с выбранной кнопкой. Запрограммированная кнопка станет зеленой, запись вернется в белую.

При следующем нажатии этой кнопки на пульте вы переключите связанный в SmartApp коммутатор.

Код

Arduino скетч (C/C++)

//*****************************************************************************
// Arduino SmartThings IR Shield
//*****************************************************************************
#include <SoftwareSerial.h>
#include <SmartThings.h>
#include <IRremote.h>

//*****************************************************************************
// Pin Definitions
//*****************************************************************************
#define PIN_LED 13
#define PIN_RECV 11
#define PIN_THING_RX 3
#define PIN_THING_TX 2

//*****************************************************************************
// Global Variables
//*****************************************************************************
SmartThingsCallout_t messageCallout;
SmartThings smartthing(PIN_THING_RX, PIN_THING_TX, messageCallout);
bool isDebugEnabled;
int stateLED;
IRrecv irrecv(PIN_RECV);
IRsend irsend;
decode_results results;

//*****************************************************************************
// API Functions
//*****************************************************************************
void setup() {
  isDebugEnabled = true;
  stateLED = 0;
  pinMode(PIN_LED, OUTPUT);
  digitalWrite(PIN_LED, LOW);
  if (isDebugEnabled) {
    Serial.begin(9600);
    Serial.println("setup..");
  }
  irrecv.enableIRIn();
}

void loop() {
  smartthing.run();
  if (irrecv.decode(&results)) {
    blue();
    irrecv.resume();
    Serial.println(results.value, HEX);
    
    String irCmd;
    if (results.decode_type == NEC) {
      irCmd = String(results.value, HEX) + "," + "NEC" + String(results.bits, DEC) + ":" + String(results.value, HEX);
    } else if (results.decode_type == SONY) {
      irCmd = String(results.value, HEX) + "," + "SNY" + String(results.bits, DEC) + ":" + String(results.value, HEX);
    } else if (results.decode_type == RC5) {
      irCmd = String(results.value, HEX) + "," + "RC5" + String(results.bits, DEC) + ":" + String(results.value, HEX);
    } else if (results.decode_type == RC6) {
      irCmd = String(results.value, HEX) + "," + "RC6" + String(results.bits, DEC) + ":" + String(results.value, HEX);
    } else {
      irCmd = String(results.value, HEX) + "," + "RAW" + String(results.bits, DEC) + ":";
    }
    Serial.println(irCmd);
    smartthing.send(irCmd);
    irCmd = "";
  }
}

void messageCallout(String message) {
  smartthing.shieldSetLED(0, 0, 0);
  if (isDebugEnabled) {
    Serial.print("Rx: '");
    Serial.print(message);
    Serial.println("' ");
  }
  String type = message.substring(0,3);
  int startCode = message.indexOf(':');
  String lenStr = message.substring(3,startCode);
  String codeStr = message.substring(startCode + 1);
  unsigned long code;
  if(type != "RAW") code = stringToNum(codeStr,16);
  int len = stringToNum(lenStr,10);
  
  if(type == "NEC") {
    Serial.println("NEC-SEND");
    Serial.println(len);
    Serial.println(code,HEX);
    irsend.sendNEC(code,len);
    irrecv.enableIRIn();
  } else if(type == "SNY") {
    irsend.sendSony(code,len);
    irrecv.enableIRIn();
  } else if(type == "RC5") {
    irsend.sendRC5(code,len);
    irrecv.enableIRIn();
  } else if(type == "RC6") {
    irsend.sendRC6(code,len);
    irrecv.enableIRIn();
  }
}

void dump(decode_results *results) {
  int count = results->rawlen;
  if (results->decode_type == UNKNOWN) Serial.print("Unknown encoding: ");
  else if (results->decode_type == NEC) Serial.print("Decoded NEC: ");
  else if (results->decode_type == SONY) Serial.print("Decoded SONY: ");
  else if (results->decode_type == RC5) Serial.print("Decoded RC5: ");
  else if (results->decode_type == RC6) Serial.print("Decoded RC6: ");
  else if (results->decode_type == PANASONIC) {
    Serial.print("Decoded PANASONIC - Address: ");
    Serial.print(results->panasonicAddress,HEX);
    Serial.print(" Value: ");
  } else if (results->decode_type == JVC) Serial.print("Decoded JVC: ");
  Serial.print(results->value, HEX);
  Serial.print(" (");
  Serial.print(results->bits, DEC);
  Serial.println(" bits)");
  Serial.print("Raw (");
  Serial.print(count, DEC);
  Serial.print("): ");
  for (int i = 0; i < count; i++) {
    if ((i % 2) == 1) Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
    else Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC);
    Serial.print(" ");
  }
  Serial.println("");
}

unsigned long stringToNum(String s, int base) {
  unsigned long i = 0, value = 0, place = s.length();
  char c;
  unsigned long sign = 1;
  for(i; i < s.length(); i++) {
    place--; c = s[i];
    if(c == '-') sign = -1;
    else if (c >= '0' && c <= '9') value += (c - '0') * exponent(base,place);
    else if (c >= 'A' && ((c - 'A' + 10) < base)) value += ((c - 'A') + 10) * exponent(base,place);
    else if (c >= 'a' && (c - 'a' + 10) < base) value += ((c - 'a') + 10) * exponent(base,place);
  }
  value *= sign;
  return value;
}

unsigned long exponent(int num, int power) {
  unsigned long total = num, i = 1;
  for(power; i < power; i++) total *= num;
  return (power == 0) ? 1 : total;
}

void green() { smartthing.shieldSetLED(0, 1, 0); }
void blue() { smartthing.shieldSetLED(0, 0, 1); }
void red() { smartthing.shieldSetLED(1, 0, 0); }
void off() { delay(100); smartthing.shieldSetLED(0, 0, 0); }

Определение устройства (Groovy)

/**
 * Smart Ir
 * Author: danny@smartthings.com
 * Date: 2013-03-06
 */
metadata {
  simulator {}
  tiles {
    standardTile("recStatus", "device.recStatus", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
      state "off", label: 'record', action: "record", backgroundColor: "#ffffff"
      state "on", label: 'record', action: "record", backgroundColor: "#ff0000"
    }
    standardTile("buttonA", "device.buttonAStatus", width: 1, height: 1, canChangeIcon: true, canChangeBackground: true) {
      state "unset", label: '', action: "buttonA", icon: "st.custom.buttons.play-pause", backgroundColor: "#cccccc"
      state "prog", label: '', action: "buttonA", icon: "st.custom.buttons.play-pause", backgroundColor: "#FDE910"
      state "set", label: '', action: "buttonA", icon: "st.custom.buttons.play-pause", backgroundColor: "#79b821"
    }
    standardTile("buttonB", "device.buttonBStatus", width: 1, height: 1, canChangeIcon: true, canChangeBackground: true) {
      state "unset", label: '', action: "buttonB", icon: "st.custom.buttons.b", backgroundColor: "#cccccc"
      state "prog", label: '', action: "buttonB", icon: "st.custom.buttons.b", backgroundColor: "#FDE910"
      state "set", label: '', action: "buttonB", icon: "st.custom.buttons.b", backgroundColor: "#79b821"
    }
    main (["buttonA","buttonB"])
    details (["recStatus","buttonA","buttonB"])
  }
}

def parse(String description) {
  def value = zigbee.parse(description)?.text
  def codeParts = value.split(/,/)
  if(device.currentValue("recStatus") == "on") {
    if(device.currentValue("lastButton") != "") {
      def buttonStatus = "${device.currentValue("lastButton")}Status"
      def buttonHex = "${device.currentValue("lastButton")}Hex"
      def buttonCode = "${device.currentValue("lastButton")}Code"
      return [
        createEvent(name:buttonStatus, value:"set", isStateChange:true),
        createEvent(name:buttonHex, value:codeParts[0], isStateChange:true),
        createEvent(name:buttonCode, value:codeParts[1], isStateChange:true),
        createEvent(name:"recStatus", value:"off", isStateChange:true),
        createEvent(name:"lastButton", value:"", isStateChange:true)
      ]
    }
  } else {
    if(codeParts[0] == device.currentValue("buttonAHex")) {
      return createEvent(name: "button", value: "A", isStateChange:true)
    } else if(codeParts[0] == device.currentValue("buttonBHex")) {
      return createEvent(name: "button", value: "B", isStateChange:true)
    }
  }
  return createEvent(name: null, value: "")
}

def record() {
  clearLast()
  if(device.currentValue("recStatus") == "on") {
    sendEvent(name:"recStatus", value:"off", isStateChange:true)
  } else {
    sendEvent(name:"recStatus", value:"on", isStateChange:true)
  }
}

def buttonA() {
  if(device.currentValue("recStatus") == "on") {
    clearLast()
    sendEvent(name:"buttonAStatus", value:"prog", isStateChange:true)
    sendEvent(name:"lastButton", value:"buttonA", isStateChange:true)
  } else if(device.currentValue("buttonAStatus") == "set") {
    zigbee.smartShield(text: "${device.currentValue("buttonACode")}").format()
  }
}

def buttonB() {
  clearLast()
  if(device.currentValue("recStatus") == "on") {
    sendEvent(name:"buttonBStatus", value:"prog", isStateChange:true)
    sendEvent(name:"lastButton", value:"buttonB", isStateChange:true)
  } else if(device.currentValue("buttonBStatus") == "set") {
    zigbee.smartShield(text: "${device.currentValue("buttonBCode")}").format()
  }
}

def clearLast() {
  if(device.currentValue("lastButton") != "") {
    sendEvent(name:"${device.currentValue("lastButton")}", value:"unset", isStateChange:true)
    sendEvent(name:"lastButton", value:"", isStateChange:true)
  }
}

SmartApp код (Groovy)

/**
 * IR Receiver
 * Author: danny@smartthings.com
 * Date: 2013-03-31
 */
preferences {
  section("Pick an IR device...") {
    input "irDevice", "device.IrBridge"
  }
  section("Button A turns on or off..."){
    input "switch1", "capability.switch", title: "This light", required: false
  }
  section("Button B turns on or off..."){
    input "switch2", "capability.switch", title: "This light", required: false
  }
}

def installed() {
  subscribe(irDevice, "button.B", handleB)
  subscribe(irDevice, "button.A", handleA)
}

def updated() {
  unsubscribe()
  subscribe(irDevice, "button.B", handleB)
  subscribe(irDevice, "button.A", handleA)
}

def handleA(evt) {
  if (switch1.currentValue("switch") == "on") switch1.off()
  else switch1.on()
}

def handleB(evt) {
  if (switch2.currentValue("switch") == "on") switch2.off()
  else switch2.on()
}

Производственный процесс

  1. Создание робота на Raspberry Pi и Python: полное руководство
  2. Сборка самобалансирующегося Segway на Raspberry Pi
  3. Использование данных в Интернете надежности: стратегии эффективного управления
  4. Высокоскоростная фотография капель воды на Arduino Nano — DIY-триггер для вспышки
  5. Датчик CO2 K30: мониторинг качества воздуха в реальном времени на Arduino
  6. Устройство для общения глухосліпых людей с помощью 1Sheeld и Arduino
  7. Умная копилка: управление монетоприёмником на Arduino Nano
  8. Управление светодиодом по Bluetooth с Arduino: простой DIY-гид
  9. Мониторинг температуры дома из любой точки через Arduino IoT Cloud
  10. Строительство рабочей силы завтрашнего дня: Как интеллектуальная автоматизация улучшает опыт сотрудников