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

Защитите свой Arduino с помощью веб-разблокировки по шаблону — простое управление и удалённый контроль

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

Arduino UNO ×1
PHPoC WiFi Shield для Arduino ×1
Сервопривод Seeed SG92R ×1
Перемычки ×1

О проекте

Введение

Если вы новичок, рекомендую ознакомиться со следующими уроками:

Вы, вероятно, знакомы с графическим ключом разблокировки на смартфоне. Теперь эту функцию можно реализовать на Arduino. Она предотвращает несанкционированный доступ к управлению и мониторингу платы.

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

Идея основана на двух проектах для платформы PHPoC:

Я адаптировал их для Arduino.

Почему выбран PHPoC WiFi Shield

PHPoC Shield имеет встроенные веб-приложения для управления Arduino без знаний веб-программирования. Также он позволяет разработчикам создавать свои веб-приложения и загружать их на шилд.

Демонстрация

На рисунке показан интерфейс разблокировки и управления сервоприводом.

Поток данных

Веб-браузер ↔ PHPoC WiFi Shield ↔ Arduino

Принцип работы

Когда пользователь рисует шаблон в браузере, он преобразуется в строку и отправляется на Arduino через WebSocket (через PHPoC Shield).

Arduino сравнивает полученную строку с заданным в коде эталонным шаблоном. При совпадении отправляется код 202 (ACCEPTED), и переменная authenticated устанавливается в true. Иначе — код 401 (DENIED) и false.

При получении команды управления Arduino сначала проверяет флаг authenticated. Если true — выполняет действие, иначе — отправляет 401.

Отображение шаблона

Шаблон преобразуется в строку чисел от 1 до 9 (как на цифровой клавиатуре). Например, на изображении шаблон соответствует строке "1,4,8,6,3".

Установлен таймаут: после периода бездействия аутентификация сбрасывается, и пользователь должен ввести шаблон заново.

Исходный код состоит из двух файлов:

Что нужно сделать

  1. Настроить WiFi на PHPoC Shield (SSID и пароль)
  2. Загрузить веб-интерфейс на PHPoC Shield
  3. Написать код для Arduino

Настройка WiFi для PHPoC Shield

См. инструкцию.

Загрузка веб-интерфейса на PHPoC Shield

Написание кода для Arduino

  • Установите библиотеку PHPoC для Arduino в Arduino IDE (инструкция).
  • Используйте исходный код из раздела кода.
  • Скомпилируйте и загрузите в Arduino через Arduino IDE.

Запуск и тест

  1. Откройте монитор порта в Arduino IDE — там будет выведен IP-адрес.
  2. В браузере перейдите по адресу https://<IP-адрес>/unlock.php
  3. Нажмите кнопку Connect и проверьте работу.

Рекомендуемый стартовый набор Arduino для начинающих

Если ищете набор, посмотрите Лучший стартовый набор Arduino для новичков.

Справочник функций

  • Библиотека Servo: attach(), write(), writeMicroseconds(), read(), attached(), detach()
  • Serial: begin(), println()
  • delay(), millis()
  • Циклы: for, while
  • Условия: if else
  • Основные функции: loop(), setup()
  • Работа со строками: toInt(), substring(), indexOf(), remove(), equals()

Код

unlock.php (веб-интерфейс)

<!DOCTYPE html>
<html>
<head>
<title>Arduino - PHPoC Shield</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7">
<meta charset="utf-8">
<style>
body { text-align: center; font-size: width/2pt; }
h1, h2, button { font-weight: bold; font-size: width/2pt; }
</style>
<script>
var CMD_AUTH = 0, CMD_CTRL = 1;
var ws, authorized = false;
var unlock_width = 400, unlock_height = 400;
var unlock_inner_radius = 14, unlock_middle_radius = 22, unlock_outer_radius = 34;
var unlock_gap = 140;
var unlock_touch_state = 0, unlock_touch_x = 0, unlock_touch_y = 0;
var unlock_touch_list = [], unlock_ratio = 1;
var servo_width = 401, servo_height = 466;
var servo_pivot_x = 200, servo_pivot_y = 200;
var servo_bracket_radius = 160, servo_bracket_angle = 0;
var servo_bracket_img = new Image();
var servo_click_state = 0, servo_last_angle = 0;
var servo_mouse_xyra = {x:0, y:0, r:0.0, a:0.0};
servo_bracket_img.src = "servo_bracket.png";

function init() {
  var unlock = document.getElementById("unlock");
  unlock.width = unlock_width; unlock.height = unlock_height;
  ["touchstart","touchend","touchmove","mousedown","mouseup","mousemove"].forEach(function(evt) {
    unlock.addEventListener(evt, window["unlock_"+evt.replace("touch","mouse")]);
  });
  var ctx = unlock.getContext("2d");
  ctx.translate(unlock_width/2, unlock_height/2);
  ctx.shadowBlur = 20; ctx.shadowColor = "LightGray";
  ctx.lineCap = "round"; ctx.lineJoin = "round";

  var servo = document.getElementById("servo");
  servo.width = servo_width; servo.height = servo_height;
  servo.style.backgroundImage = "url('/servo_body.png')";
  ["touchstart","touchend","touchmove","mousedown","mouseup","mousemove"].forEach(function(evt) {
    servo.addEventListener(evt, window["servo_"+evt.replace("touch","mouse")]);
  });
  ctx = servo.getContext("2d");
  ctx.translate(servo_pivot_x, servo_pivot_y);
  update_view();
}

function connect_onclick() {
  if(ws == null) {
    var ws_host_addr = "";
    if((navigator.platform.indexOf("Win") != -1) && (ws_host_addr.charAt(0) == "[")) {
      ws_host_addr = ws_host_addr.replace(/[\[\]]/g, '').replace(/:/g, "-") + ".ipv6-literal.net";
    }
    ws = new WebSocket("ws://" + ws_host_addr + "/web_pattern", "text.phpoc");
    document.getElementById("ws_state").innerHTML = "CONNECTING";
    ws.onopen = ws_onopen;
    ws.onclose = ws_onclose;
    ws.onmessage = ws_onmessage;
  } else ws.close();
}

function ws_onopen() {
  document.getElementById("ws_state").innerHTML = "<font color='blue'>CONNECTED</font>";
  document.getElementById("bt_connect").innerHTML = "Disconnect";
  update_view();
}

function ws_onclose() {
  document.getElementById("ws_state").innerHTML = "<font color='gray'>CLOSED</font>";
  document.getElementById("bt_connect").innerHTML = "Connect";
  ws.onopen = ws.onclose = ws.onmessage = null; ws = null;
  authorized = false; update_view();
}

function ws_onmessage(e_msg) {
  var resp = parseInt((e_msg || window.event).data);
  if(resp == 202) authorized = true;
  else if(resp == 401) authorized = false;
  else console.log("unknown:"+resp);
  update_view();
}

function update_view() {
  authorized ? servo_update_view() : unlock_update_view();
}

function unlock_update_view() {
  document.body.style.backgroundColor = "black";
  document.body.style.color = "white";
  document.getElementById('unlock_area').style.display = 'block';
  document.getElementById('control_area').style.display = 'none';
  var ctx = document.getElementById("unlock").getContext("2d");
  ctx.clearRect(-unlock_width/2, -unlock_height/2, unlock_width, unlock_height);
  ctx.lineWidth = 10; ctx.strokeStyle = "white"; ctx.globalAlpha = 1;
  ctx.beginPath();
  for(var i=0;i max_r) return false;
  if(rc_y < -width || rc_y > width) return false;
  return true;
}

function servo_mouse_down() {
  if(event.touches && event.touches.length>1) servo_click_state = event.touches.length;
  if(servo_click_state>1) return;
  if(check_range_xyra(event, servo_mouse_xyra)) { servo_click_state=1; servo_last_angle = servo_mouse_xyra.a/Math.PI*180.0; }
}
function servo_mouse_up() { servo_click_state=0; }
function servo_mouse_move() {
  if(event.touches && event.touches.length>1) servo_click_state = event.touches.length;
  if(servo_click_state>1) return; if(!servo_click_state) return;
  if(!check_range_xyra(event, servo_mouse_xyra)) { servo_click_state=0; return; }
  var angle = servo_mouse_xyra.a/Math.PI*180.0;
  if(Math.abs(angle)>90 && angle*servo_last_angle<0) {
    servo_last_angle = (servo_last_angle>0) ? -180 : 180;
  }
  servo_bracket_angle += (servo_last_angle - angle);
  servo_last_angle = angle;
  if(servo_bracket_angle > 90) servo_bracket_angle = 90;
  if(servo_bracket_angle < -90) servo_bracket_angle = -90;
  servo_update_view();
  send_to_Arduino(CMD_CTRL, Math.floor(servo_bracket_angle));
  document.getElementById("debug").innerHTML = Math.floor(servo_bracket_angle);
  event.preventDefault();
}

function send_to_Arduino(cmd, data) {
  if(ws.readyState == 1) ws.send(cmd + ":" + data + "\r\n");
}

window.onload = init;
</script>
</head>
<body>
<h1>Arduino - Web Pattern Unlock</h1>
<div id="unlock_area" style="display:block;"><canvas id="unlock"></canvas></div>
<div id="control_area" style="display:none;"><canvas id="servo"></canvas><p>Angle: <span id="debug">0</span></p></div>
<h2>WebSocket: <span id="ws_state">null</span> <button id="bt_connect" onclick="connect_onclick();">Connect</button></h2>
</body>
</html>

ArduinoUnlockExample.ino

/* Arduino Web Server - Pattern Unlock */
#include "SPI.h"
#include "Phpoc.h"
#include 

#define CMD_AUTH 0
#define CMD_CTRL 1
#define ACCEPTED "202"
#define UNAUTHORIZED "401"

PhpocServer server(80);
Servo servo;
String pattern;
bool authenticated;
unsigned long timeout = 10000;
unsigned long lastActiveTime = 0;

void setup() {
  Serial.begin(9600);
  while(!Serial);
  Phpoc.begin(PF_LOG_SPI | PF_LOG_NET);
  server.beginWebSocket("web_pattern");
  Serial.print("WebSocket server address: ");
  Serial.println(Phpoc.localIP());
  servo.attach(8);
  servo.write(90);
  pattern = "1,4,8,6,3";
  authenticated = false;
  lastActiveTime = 0;
}

void loop() {
  PhpocClient client = server.available();
  if (client) {
    String data = client.readLine();
    if(data) {
      int pos = data.indexOf(':');
      int cmd = data.substring(0, pos).toInt();
      if(cmd == CMD_AUTH) {
        String reqPattern = data.substring(pos+1);
        reqPattern.remove(reqPattern.indexOf(13));
        reqPattern.remove(reqPattern.indexOf(10));
        if(pattern.equals(reqPattern)) {
          authenticated = true;
          server.write(ACCEPTED, 3);
          lastActiveTime = millis();
        } else {
          authenticated = false;
          server.write(UNAUTHORIZED, 3);
        }
      } else if(cmd == CMD_CTRL) {
        if(authenticated) {
          int angle = data.substring(pos+1).toInt();
          angle = map(angle, 90, -90, 0, 180);
          servo.write(angle);
          lastActiveTime = millis();
          Serial.println(angle);
        } else {
          server.write(UNAUTHORIZED, 3);
        }
      }
    }
  }
  if (authenticated && (millis() - lastActiveTime > timeout)) {
    authenticated = false;
    server.write(UNAUTHORIZED, 3);
  }
}

Схема подключения

Схема показывает подключение PHPoC WiFi Shield к Arduino UNO и сервопривода к выводу 8.

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

  1. Эволюция и производство массовых выкроек одежды
  2. Веб-управляемая DMX-система освещения: Arduino Mega как мастер-контроллер
  3. Сборка Bluetooth-робота-шпиона на Arduino с управлением с телефона
  4. FlickMote: жестовое IR-пульт для умного дома на Arduino 101 и ультразвуковом датчике
  5. DIY Arduino TV-B-Gone: универсальный пульт для выключения любого телевизора
  6. Создание пользовательских LED-часов с будильником — видно с 12 метров
  7. Find Me: Умный поисковик вещей на Arduino и Bluetooth
  8. Оптимизированные решения питания для проектов на Arduino
  9. Крестики-нолики на Arduino с матрицей MAX7219 и картонным корпусом
  10. Пошаговое руководство: сборка умного четырёхногого робота на Arduino