====== Счетчик лайков с конфетами ======
{{ :projects:counter-like:counter-like_overview.jpg |}}
* Платформы: Arduino
* Языки программирования: Arduino (C++), PHP
* Тэги: IoT Arduino, лайки, интернет вещей, facebook
===== Что это =====
Соберём счетчик отметок «Нравится» для страницы Facebook, выдающий конфету за каждый новый лайк.
===== Видеообзор ======
{{youtube>zDKKUEoomqs?large}}
===== Что понадобится =====
{{ :projects:counter-like:counter-like_parts.jpg |}}
- [[amp>product/iskra-neo?utm_source=announce&utm_campaign=mf17_robot&utm_medium=wiki | Iskra Neo]]
- [[amp>product/arduino-troyka-slot-shield?utm_source=announce&utm_campaign=mf17_robot&utm_medium=wiki | Troyka Slot Shield]]
- [[amp>product/troyka-wi-fi?utm_source=announce&utm_campaign=mf17_robot&utm_medium=wiki | Wi-Fi (Troyka-модуль)]]
- [[amp>product/troyka-quad-display?utm_source=announce&utm_campaign=mf17_robot&utm_medium=wiki | Четырёхразрядный индикатор]]
- [[amp>product/troyka-button?utm_source=announce&utm_campaign=mf17_robot&utm_medium=wiki | Кнопка (Troyka-модуль)]]
- [[amp>product/servo-fs90?utm_source=announce&utm_campaign=mf17_robot&utm_medium=wiki | Микросервопривод FS90]]
- [[amp>product/usb-cable-micro?utm_source=announce&utm_campaign=mf17_robot&utm_medium=wiki | Кабель USB (A — Micro USB)]]
- [[amp>product/usb-power-plug-2a?utm_source=announce&utm_campaign=mf17_robot&utm_medium=wiki | Импульсный блок питания с USB-разъемом (5 В, 2100 мА)]]
- Штырьковые соединители угловые (1×40)
- Оргстекло: 400×300×3 мм
- Фанера ФК: 600×400×6 мм
- Фанера ФК: 400×300×18 мм
- Крепёжные материалы: винты и гайки
- Конфеты «Skittles»
===== Как собрать =====
Сборка устройства состоит из аппаратной и программной части.
==== Hardware-часть ====
- Установите Troyka Slot Shield на Iskra Neo.{{ :projects:counter-like:counter-like_build1.jpg |}}
- Подключите Wi-Fi (Troyka-модуль) к Troyka Slot Shield:
- пин ''TX'' Wi-Fi модуля к цифровому пину ''0'' Troyka Slot Shield
- пин ''RX'' — к цифровому пину ''1'' Troyka Slot Shield.{{ :projects:counter-like:counter-like_build2.jpg |}}
- Вставьте Четырёхразрядный индикатор (Troyka-модуль) на Troyka Slot Shield:
- пин ''CS'' дисплея к цифровому пину ''9'' Troyka Slot Shield
- пин ''DI'' — к пину ''DO'' Troyka Slot Shield.{{ :projects:counter-like:counter-like_build3.jpg |}}
- Подключите кнопку (Troyka-модуль) к цифровому пину ''2'' Troyka Slot Shield.{{ :projects:counter-like:counter-like_build4.jpg |}}
- Подключите сервопривод через угловые штырьки к цифровому пину ''3'' Troyka Slot Shield.{{ :projects:counter-like:counter-like_build5.jpg |}}
- Установите собранную конструкцию на корпус устройства.{{ :projects:counter-like:counter-like_build6.jpg |}}
- На обратной стороне корпуса через специальные вставки закрепите сервопривод.{{ :projects:counter-like:counter-like_build7.jpg |}}
Общий вид устройства.{{ :projects:counter-like:counter-like_build8.jpg |}}
Переходите к программной части.
==== Software-часть ====
Социальные сети: [[https://www.facebook.com/|Facebook]], [[https://vk.com/|VK]] и другие работают через протокол [[https://ru.wikipedia.org/wiki/HTTPS|HTTPS]]. Микроконтроллер ESP8266 на борту платы [[amp>product/troyka-wi-fi?utm_source=announce&utm_campaign=mf17_robot&utm_medium=wiki | Wi-Fi (Troyka-модуль)]] в исходной конфигурации работает через [[https://ru.wikipedia.org/wiki/AT-%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B|АТ-команды]]. В результате работа напрямую с HTTPS-протоколом не возможна.
Для решения проблемы используем небольшой php-скрипт, который необходимо разместить на хостинге. В качестве примера воспользуемся бесплатным хостингом [[https://www.000webhost.com/|«000webhost»]]
- Зарегистрируйтесь на хостинге. В результате прохождение всех процедур регистрации хостинга и домена приведет к следующим результатам: наличие полного доменного имени и доступа к файловой системе на предоставленном сервере. В нашем случае:
- Полное доменное имя: http://amperkalikes.000webhostapp.com
- Доступ авторизованного пользователя к файловой системе по адресу: https://files.000webhost.com
- Скачайте и откройте [[projects:counter-like#php-скрипт|php-скрипт]]. Данный скрипт позволяет открыть целевую страницу «facebook», получить искомое количество лайков на странице и выгрузить его в формате: ''fan_count=xxxx''.
Чтобы скрипт выдавал количество лайков вашей страницы, его требуется изменить. Для этого нужно внести изменения в переменную ''$id'', определенную в третьей строке кода скрипта. Значение переменной следует заменить на значение ''id'' вашей страницы «facebook». Чтобы узнать значение ''id'' вашей страницы, нужно перейти на интересующую нас страницу и проанализировать ее адрес.
В качестве примера возьмем адрес facebook-страницы Амперки:https://www.facebook.com/amperka.ru/?fref=ts
''id'' страницы расположено между слешами после домена ''www.facebook.com'', следовательно, ''id-страницы'' — «amperka.ru» Присвоим это значение переменной $id='amperka.ru'.
Теперь разместим наш модифицированный скрипт на сервере. В нашем случае нужно перейти по адресу: https://files.000webhost.com
и простым перетягиванием ярлыка файла скрипта (drag-and-drop) перенести файл ''getLikes.php'' в файловую систему сервера.
В заключении проверьте успешность работы скрипта. Для этого перейдите по адресу:http://amperkalikes.000webhostapp.com/getLikes.php
Если при этом веб-браузер отобразит пустое окно с единственной строкой: ''fan_count=4,218'' (число может быть иным), то все сделано верно.
===== Исходный код =====
==== Программа для Arduino ====
// библиотека для работы с сервоприводами
#include
// библиотека для работы с дисплеем
#include "QuadDisplay2.h"
#include "TimeCheck.h"
// буффер запроса
char serialbuffer[100];
// создаём объект класса QuadDisplay и передаём номер пина CS
QuadDisplay qd(9);
// создаём объект для работы с сервоприводом
Servo srv;
TimeCheck butTime(500);
TimeCheck timeOut(5000);
TimeCheck autoRun(1000);
int but = 2;
int srvPin = 3;
int ang0 = 110;
int ang1 = 140;
String wifi = "nameWiFi";
String passwordWifi = "passwordWiFi";
String host = "amperkalikes.000webhostapp.com";
String link = "getLikes.php";
String cmdWifi;
String cmdHost;
String cmdLink;
int pIndex = -1;
boolean autoRunOn = false;
int fanReceived = -1;
int fanMemory = -1;
String makeWifi() {
String toReturn = "AT+CWJAP=\"";
toReturn += wifi;
toReturn += "\",\"";
toReturn += passwordWifi;
toReturn += "\"";
return toReturn;
}
String makeGet() {
String toReturn = "GET /";
toReturn += link;
toReturn += " HTTP/1.1\r\nHost:";
toReturn += host;
toReturn += "\r\n\r\n\r\n";
return toReturn;
}
String makeHost()
{
String toReturn = "AT+CIPSTART=\"TCP\",\"";
toReturn += host;
toReturn += "\",80";
return toReturn;
}
void setup()
{
Serial1.begin(115200);
Serial.begin(115200);
qd.begin();
qd.displayInt(-42);
pinMode(but, INPUT);
srv.write(ang0);
srv.attach(srvPin);
srv.write(ang0);
cmdWifi = makeWifi();
cmdHost = makeHost();
cmdLink = makeGet();
qd.displayInt(-3);
Serial.print("cmdWifi = ");
Serial.println(cmdWifi);
Serial.print("cmdHost = ");
Serial.println(cmdHost);
Serial.print("cmdLink = ");
Serial.println(cmdLink);
}
void loop()
{
if(timeOut.check() && pIndex != -1) {
Serial.print("timeOut.check() : last pIndex = ");
Serial.println(pIndex);
pIndex = -1;
}
if(buttCheck()) {
autoRunOn = !autoRunOn;
}
switch(pIndex) {
case -1:
if(autoRun.check() && autoRunOn) {
Serial.println("autoRun ON +++++++++++++");
pIndex = 0;
}
break;
case 0:
checkStatConn();
pIndex++;
timeOut.defer();
break;
case 10:
startTCP();
pIndex++;
timeOut.defer();
break;
case 20:
requestLikes();
pIndex++;
timeOut.defer();
break;
case 30:
qd.displayInt(fanReceived);
fanCheck();
pIndex = -1;
autoRun.defer();
break;
}
while(Serial1.available() > 0) {
String tmp = Serial1.readStringUntil('\n');
if (true) {
Serial.println(tmp);
}
int valueStat = getStatus(tmp);
switch(valueStat) {
//got IP, TCP connection next
case 2:
pIndex = 10;
break;
//TCP is good, getLikes next
case 3:
pIndex = 20;
break;
//got IP, TCP connection next
case 4:
pIndex = 10;
break;
//Problems with WiFi connection
case 5:
Serial.println("Check Wi-Fi settings");
Serial.print("Wifi settings now : ");
Serial.println(cmdWifi);
Serial1.println("AT+CWMODE=3");
delay(2000);
Serial1.println(cmdWifi);
pIndex = -1;
break;
}
if (getConnect(tmp)) {
pIndex = 20;
}
if(getFanCount(tmp) > 0) {
pIndex = 30;
}
}
}
boolean buttCheck() {
if(!digitalRead(but) && butTime.check()) {
return true;
} else {
return false;
}
}
void checkStatConn() {
Serial1.println("AT+CIPSTATUS");
}
void startTCP() {
Serial.println("startTCP");
Serial1.println(cmdHost);
}
int getStatus(String input) {
if (!input.startsWith("STATUS:"))
return -1;
input.replace("STATUS:","");
return input.toInt();
}
boolean getConnect(String input) {
if (!input.startsWith("CONNECT")) {
return false;
}
return true;
}
void doRequest(String input) {
Serial1.print("AT+CIPSEND=");
Serial1.println(input.length());
if(Serial1.find(">")){
Serial.println(">");
} else {
Serial1.println("AT+CIPCLOSE");
Serial.println("Connect timeout");
return;
}
Serial1.print(input);
}
void requestLikes() {
doRequest(cmdLink);
}
int getFanCount(String input) {
if (!input.startsWith("fan_count=")) {
return -1;
}
input.replace("fan_count=","");
input.replace(",","");
fanReceived = input.toInt();
Serial.print("getFanCount() : fanReceived = ");
Serial.println(fanReceived);
return input.toInt();
}
void giveCandy() {
srv.write(ang1);
delay(2000);
srv.write(ang0);
delay(2000);
}
void fanCheck() {
if (fanReceived - fanMemory > 20 || fanReceived < fanMemory) {
fanMemory = fanReceived;
} else {
while (fanMemory < fanReceived) {
giveCandy();
++fanMemory;
}
}
}
==== PHP-скрипт ====
<?php
$id='amperka.ru';
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en\r\n" .
"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n",
"Cookie: foo=bar\r\n"
)
);
$context = stream_context_create($opts);
// Open the file using the HTTP headers set above
$file = file_get_contents('https://www.facebook.com/plugins/fan.php?connections=100&id='.$id, false, $context);
//echo $file;
$target = '_1drq';
$target1 = ';">';
$target2 = ' ';
$pos = strstr($file, $target);
$pos = strstr($pos, $target1);
$pos = strstr($pos, $target2, true);
$pos = substr($pos, strlen($target1));
print('fan_count=');
print_r($pos);
//echo $pos;
?>
==== Ресурсы ====
* Библиотека [[https://github.com/amperka/TimeCheck|TimeCheck]] для работы выше приведённого скетча.
* {{:projects:counter-like:amperkacandymachine.zip|Исходник для изготовления корпуса}}