📜 ⬆️ ⬇️

Tracking statistics in WoT using Arduino



Hi, Habr. Remembering my engineering youth, I wanted to look around the glands again. Returning to PIC'acm and programming on asm was frankly lazy (traumatic childhood memories of manual work without third-party libraries with i2c and HD44780 bus), so I went online and found out about the existence of the Arduino platform.

A quick glance showed that this is just what I need to satisfy the nostalgic urges. A week ago, a set was purchased. To flash the LED to the former engineer of electronics with five years of experience is somehow not comme il faut, that's why the idea of ​​a statistics gauge in tanks was born (I confess, it’s a sin ...). This is my peculiar “Hello, Habr!” And “Hello, World!”.

The idea is simple - monitor the Wargaming statistics server and notify the user about his game successes (or vice versa). I decided to monitor with the help of the Wargaming API, since the idea of ​​parsing web pages of foreign resources rested on the size of the RAM (8kb per receive) used to access the shield on the W5100 controller.
')
To display the information I took what was at hand - the standard 1602 display. But that would not be too trivial, I decided to connect it via the shift register 74HC595. A quick search proved the old truth that everything has already been invented before us: link . The display sits on the SPI bus and additionally uses one pin to select the device (I have the 3rd). For successful compiling, you need to replace the LiquidCrystal library with the modified one from the link above. Also, by the link above, the author forgot to put the r / w pin of the display on the ground, which is why he initially thought that the example was not working. Just in case my crazy board:
Breadboard

I also wanted to implement the logging of achievements on the SD card, but decided to leave for the future, as well as a small web server with monitoring results.

Sketch
#include <SPI.h>
#include <Ethernet.h>
#include <LiquidCrystal.h>

#define ETHERNET_PIN 10
#define LCD_PIN 3

// Forced IP address on the network
IPAddress ip (192, 168, 1, 40);

// MAC
byte mac [] = {0x42, 0x42, 0x42, 0x42, 0x42, 0x42};

// Server, registered ID, profile number
const char server [] = "api.worldoftanks.ru";
const char application_id [] = "demo";
const char account_id [] = "4848655";

// Update frequency in milliseconds
const unsigned int UpdateDelta = 20000;
// Remaining before the update
unsigned int UpdateTime = 0;

// Network Client
Ethernet Client;
// LCD
LiquidCrystal lcd (LCD_PIN);

byte newChar1 [8] = {
B00100,
B01110,
B10101,
B00100,
B00100,
B00100,
B00100,
B00000
};

byte newChar2 [8] = {
B00100,
B00100,
B00100,
B00100,
B10101,
B01110,
B00100,
B00000
};

// Status of parsing
enum ReadStatusEnum {
WiteTag,
ReadTag,
WiteValue
} ReadStatus = WiteTag;

String nickname = "Unknown Noob";
long WG_rating, pre_WG_rating, buf_WG_rating = 0;
unsigned long battles, pre_battles, buf_battles = 0;
unsigned long wins, pre_wins, buf_wins = 0;
unsigned long damage, pre_damage, buf_damage = 0;
unsigned long frags, pre_frags, buf_frags = 0;

String LCD_strings [6];

// Looking for the right tags
void FilterData (String SectionTagName, String TagName, String Value)
{
if (SectionTagName.compareTo ("statistics") == 0) {
if (TagName.compareTo ("nickname") == 0)
nickname = Value;
if (TagName.compareTo ("global_rating") == 0)
buf_WG_rating = Value.toInt ();
}
if (SectionTagName.compareTo ("all") == 0) {
if (TagName.compareTo ("battles") == 0)
buf_battles = Value.toInt ();
if (TagName.compareTo ("wins") == 0)
buf_wins = Value.toInt ();
if (TagName.compareTo ("damage_dealt") == 0)
buf_damage = Value.toInt ();
if (TagName.compareTo ("frags") == 0)
buf_frags = Value.toInt ();
}
}

void readServer ()
{
// We're kicking
if (client.connect (server, 80)) {
client.print ("GET / wot / account / info /? application_id =");
client.print (application_id);
client.print ("& account_id =");
client.print (account_id);
client.println ("HTTP / 1.1");
client.print (“Host:„);
client.println (server);
client.println (“User-Agent: arduino-ethernet”);
client.println ("Accept: text / html");
client.println (“Connection: close”);
client.println ();

// Waiting for readiness
bool Wait = true;
unsigned int Time = 0;
while (Wait)
{
Wait =! Client.available ();
if (Time> 200) Wait = false;
Time ++;
delay (10);
}

char symbol = '';
char pre_symbol = '';
String TagName = "";
String SectionTagName = "";
String Value = "";
String PreSectionTagName = "";

ReadStatus = WiteTag;

// Repeat until buffer is empty
while (client.available ()) {
// Read the byte from the buffer
pre_symbol = symbol;
symbol = client.read ();
//Serial.print (symbol);
if (ReadStatus == WiteTag && pre_symbol == '"' && symbol! = ':') {
// Found the beginning of the tag
ReadStatus = ReadTag;
TagName = "";
}

if (ReadStatus == ReadTag) {
if (symbol! = '"') {
// Read the tag name
TagName + = symbol;
}
else
{
// Found end of tag
Value = "";
ReadStatus = WiteValue;
}
}

if (ReadStatus == WiteValue) {
if (symbol == ',' || symbol == '}') {
// End of value
ReadStatus = WiteTag;
FilterData (SectionTagName, TagName, Value);
if (symbol == '}') {
// End of section
SectionTagName = PreSectionTagName;
}
}
else {
if (symbol == '{') {
// Start section
PreSectionTagName = SectionTagName;
SectionTagName = TagName;
ReadStatus = WiteTag;
}
else {
// Read the value
if (symbol! = ':' && symbol! = '"' && symbol! = '')
Value + = symbol;
}
}
}
}
}
// Stop Client
client.flush ();
client.stop ();
}

void generateSrings ()
{
if (pre_battles == 0 || battles == 0) {
//Initialization
pre_WG_rating = buf_WG_rating;
WG_rating = buf_WG_rating;
pre_battles = buf_battles;
battles = buf_battles;
pre_wins = buf_wins;
wins = buf_wins;
pre_damage = buf_damage;
damage = buf_damage;
pre_frags = buf_frags;
frags = buf_frags;
}

if (buf_battles> battles)
{
// It was updated stats
pre_WG_rating = WG_rating;
WG_rating = buf_WG_rating;
pre_battles = battles;
battles = buf_battles;
pre_wins = wins;
wins = buf_wins;
pre_damage = damage;
damage = buf_damage;
pre_frags = frags;
frags = buf_frags;
}

if (pre_battles == battles)
{
LCD_strings [0] = nickname + "";
LCD_strings [0] = LCD_strings [0] .substring (0.16);

LCD_strings [1] = "Btl:" + String (battles) + "-";
LCD_strings [1] = LCD_strings [1] .substring (0.16);

float wins_percent = (float) wins / (float) battles * 100.0;
LCD_strings [2] = "Wins:" + String (wins_percent) + "-";
LCD_strings [2] = LCD_strings [2] .substring (0.16);

float avrage_damage = (float) damage / (float) battles;
String D = String (avrage_damage);
D = D. Substring (0, D.length () - 1);
LCD_strings [3] = "Dmg:" + D + "-";
LCD_strings [3] = LCD_strings [3] .substring (0.16);

float avrage_frags = (float) frags / (float) battles;
LCD_strings [4] = "Frag:" + String (avrage_frags) + "-";
LCD_strings [4] = LCD_strings [4] .substring (0.16);

LCD_strings [5] = "WG:" + String (WG_rating) + "-";
LCD_strings [5] = LCD_strings [5] .substring (0.16);
}
else
{
LCD_strings [0] = nickname + "";
LCD_strings [0] = LCD_strings [0] .substring (0.16);

LCD_strings [1] = "Btl:" + String (battles) + "" + char (0x01) + String (battles-pre_battles) + "";
LCD_strings [1] = LCD_strings [1] .substring (0.16);

float wins_percent = (float) wins / (float) battles * 100.0;
float pre_wins_percent = (float) pre_wins / (float) pre_battles * 100.0;
char Delta = char (0x01);
if (wins_percent <pre_wins_percent) Delta = char (0x02);
LCD_strings [2] = "Wins:" + String (wins_percent) + "" + Delta + String (abs (wins_percent - pre_wins_percent)) + "";
LCD_strings [2] = LCD_strings [2] .substring (0.16);

float avrage_damage = (float) damage / (float) battles;
float pre_avrage_damage = (float) pre_damage / (float) pre_battles;
Delta = char (0x01);
if (avrage_damage <pre_avrage_damage) Delta = char (0x02);
String D = String (avrage_damage);
D = D. Substring (0, D.length () - 1);
LCD_strings [3] = "Dmg:" + D + "" + Delta + String (abs (avrage_damage - pre_avrage_damage)) + "";
LCD_strings [3] = LCD_strings [3] .substring (0.16);

float avrage_frags = (float) frags / (float) battles;
float pre_avrage_frags = (float) pre_frags / (float) pre_battles;
Delta = char (0x01);
if (avrage_frags <pre_avrage_frags) Delta = char (0x02);
LCD_strings [4] = "Frag:" + String (avrage_frags) + "" + Delta + String (abs (avrage_frags - pre_avrage_frags)) + "";
LCD_strings [4] = LCD_strings [4] .substring (0.16);

Delta = char (0x01);
if (WG_rating <pre_WG_rating) Delta = char (0x02);
LCD_strings [5] = "WG:" + String (WG_rating) + "" + Delta + String (abs (WG_rating - pre_WG_rating)) + "";
LCD_strings [5] = LCD_strings [5] .substring (0.16);
}
}

void PrintMSG (int LCD_tick, int ScrNum)
{
if (LCD_tick <= 16)
{
lcd.setCursor (0, 0);
lcd.print (LCD_strings [ScrNum * 2 + 0] .substring (0, LCD_tick) + "_");
}
else
{
lcd.setCursor (0, 1);
lcd.print (LCD_strings [ScrNum * 2 + 1] .substring (0, LCD_tick-16) + "_");
}
}

unsigned int LCD_Screen = 0;
unsigned int LCD_tick = 0;
void UpdateLCD (unsigned int UpdateTime)
{
if (UpdateTime> UpdateDelta / 3 * 2)
{
// first screen
if (LCD_Screen! = 0) {
LCD_Screen = 0;
LCD_tick = 0;
}
PrintMSG (LCD_tick, LCD_Screen);
}
else
{
if (UpdateTime> UpdateDelta / 3)
{
// Second screen
if (LCD_Screen! = 1) {
LCD_Screen = 1;
LCD_tick = 0;
}
PrintMSG (LCD_tick, LCD_Screen);
}
else
{
// third screen
if (LCD_Screen! = 2) {
LCD_Screen = 2;
LCD_tick = 0;
}
PrintMSG (LCD_tick, LCD_Screen);
}
}

LCD_tick ++;
if (LCD_tick> 32) LCD_tick = 32;
}

void setup ()
{
// Initialize the display
lcd.createChar (1, newChar1);
lcd.createChar (2, newChar2);
lcd.begin (16, 2);

// Initialize Serial Port
//Serial.begin(57600);
pinMode (ETHERNET_PIN, OUTPUT);
digitalWrite (ETHERNET_PIN, LOW);
delay (1000);
Ethernet.begin (mac, ip);
delay (1000);
digitalWrite (ETHERNET_PIN, HIGH);
}

void loop ()
{
// Requesting the stat
if (UpdateTime == 0) {
UpdateTime = UpdateDelta;
digitalWrite (ETHERNET_PIN, LOW);
readServer ();
digitalWrite (ETHERNET_PIN, HIGH);
generateSrings ();
}

UpdateLCD (UpdateTime);
delay (100);
UpdateTime - = 100;
}

But a demonstration of work. Unfortunately, Wargaming servers update statistics only after the game session ends:



And finally, a fly in the ointment - for reasons I don't understand, after a while, the device stops taking statistics from the server. By debag and indicators, it is clear that the request is leaving, but there is no answer. I hope this is due to my crooked tuned router.
Upd. No longer relevant, corrected sketch

Source: https://habr.com/ru/post/242477/


All Articles