📜 ⬆️ ⬇️

Visual monitoring of a large number of objects (for example, IPTV channels) using Arduino

In this article I will tell you how I implemented my old idea - a visual display of the state of IPTV channels. In general, initially it was all about monitoring - for example, a map of the city, LEDs were placed on it (in the places where the equipment is located), and looking at this map you can always clearly see what happened where it broke.
But in my case we are talking about IPTV channels.

We have a lot of these channels, almost 160 of them, not counting service channels, of which the federalka is multiplexed (for example, TNT channel is taken from two receivers located in different parts of the city (ideally, of course, I want to come from another city), multicast private streams are driven into a multiplexer, which already produces one public multicast, while in case of a failure of one of the channels it automatically switches to the reserve.

Naturally, I monitored software monitoring, i.e. made a whole complex of, for example, scripts that run through all channels - subscribe to them, check if there are any errors in the stream, if the channel coding has failed, trying to fix them by distorting the cam modules (using telnet, snmp) just trite rebooting the receiver if the number of failed channels coming from him more than half, of course, sms-ka me about all the significant events. Also, statistics on the entire network are collected from STB-NIS, from switches, which firmware people have, which consoles, which channels and which programs people watch most of all (very curious data by the way).

For clarity, there is a program that runs through the channels in the form of a mosaic, or holds a certain
part of the channels on the screen (all 160 channels, you know, do not fit on one screen, but 4x6 = 24 SD channels on a computer with good process / video / network card is quite real).
')
In general, programmatically, all this is already there, but so that without a computer and in the form of LEDs - it was not ...
And then I met with Arduino.
You probably understand what it led to.

Since I was not friends with a soldering iron (and even now I am not strong - but I hope to have certain progress), and I was not at all friendly with circuitry, etc. - It was hard for me at first (and now, too), but that was the goal - to learn something new, to know the unknown before. I will not dwell on how in the process I learned about such things as shift registers, insights, how one can control a whole array of LEDs, using such a phenomenon as “dynamic indication”. Just tell you what happened in the end (and I did it!).

clickable

So, I soldered a matrix of 16x10 LEDs to the finished prototype board, connected them through 4 shift registers 74HC595. Used arduino and ethershield on enc28j60 for it.
It turned out about here (pictures are clickable)

clickable

clickable

clickable

The code for the development environment with version 0.22 and the ethershield version 1.1 library.
Already at the moment I know for sure that there is a newer, if you suddenly want to repeat it, you may have to adapt

 #include "etherShield.h" static uint8_t mymac[6] = {0x00,0x80,0x48,0x2d,0xf7,0x25}; //  mac-  static uint8_t myip[4] = {10,20,30,40}; // ip- 10.20.30.40 #define MYPORT 5555 #define BUFFER_SIZE 500 static uint8_t buf[BUFFER_SIZE+1]; static char number[7]; const byte clockPin = 7; // const byte latchPin = 8; //         const byte dataPin = 9; // const byte NumRegs = 4; //    const byte NumCols=10; const byte NumRows=16; //      -       , //       //    4 ,       , //   //     ()   1  32 //     26  (10+16) -      byte Col_bits[NumCols] = {3,5,7,11,13,15,19,21,23,27}; //         //    , .. 1-  //    3    .. byte Row_bits[NumRows] = {32,30,28,26,24,22,20,18,16,14,12,10,8,6,4,2}; //      //      byte Regs[NumRegs]; int reg_n, bit_n, in_r, in_c; // , . //       2! ;) // -   byte matrix[NumRows][NumCols]={{1,0,1,0,0,0,1,1,1,1}, {1,0,1,0,0,0,0,0,0,1}, {1,0,1,0,0,0,0,0,0,1}, {1,0,1,0,0,0,0,0,1,0}, {1,0,1,0,0,0,0,0,1,0}, {1,0,1,1,0,0,0,0,1,0}, {1,0,1,0,1,0,0,1,0,0}, {1,0,1,0,1,0,0,1,0,0}, {1,0,1,0,1,0,0,1,0,0}, {1,0,1,0,1,0,1,0,0,0}, {1,0,1,0,1,0,1,0,0,0}, {1,0,1,1,0,0,1,1,1,1}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}}; EtherShield es=EtherShield(); void setup() { pinMode(latchPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(clockPin, OUTPUT); es.ES_enc28j60Init(mymac); //   es.ES_init_ip_arp_udp_tcp(mymac,myip, MYPORT); //   } void loop() { uint16_t plen, dat_p, ptr; while(1) { burn_matrix(); //          //        ( ).    //       ,     //     -      //   - read packet, handle ping and wait for a tcp packet: dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf)); /* dat_p will be unequal to zero if there is a valid request */ if(dat_p == 0) { // no request continue; } //             :) //        "IbZ " if (strncmp("IbZ ",(char *)&(buf[dat_p]),4)==0) { //   4-       ptr = dat_p+4; for(in_r=0; in_r < NumRows; in_r++) { for(in_c=0; in_c < NumCols; in_c++) { matrix[in_r][in_c] = 0; //    ( ,    ;) ) } } //    -   -   //   ,   - 0 while(buf[ptr] != 0) { in_r = (buf[ptr]-1) % 16; in_c = (buf[ptr]-1) / 16; matrix[in_r][in_c] = 1; //     ptr++; } } } } void burn_matrix() { //     -  1- ,  , //  2- ,       10-  for(int c = 0; c < NumCols; c++) { for(int i = 0; i < NumRegs; i++) { Regs[i]=255; } reg_n = (Col_bits[c]-1) / 8; bit_n = (Col_bits[c]-1) % 8; bitWrite(Regs[reg_n], bit_n, 0); for(int r = 0; r < NumRows; r++) { reg_n = (Row_bits[r]-1) / 8; bit_n = (Row_bits[r]-1) % 8; bitWrite(Regs[reg_n], bit_n, matrix[r][c]); } registerWrite(); delay(1); } } //      -     void registerWrite() { digitalWrite(latchPin, LOW); for(int cur_reg = NumRegs-1; cur_reg >= 0; cur_reg-- ) { shiftOut(dataPin, clockPin, MSBFIRST, Regs[cur_reg]); } digitalWrite(latchPin, HIGH); } 
#include "etherShield.h" static uint8_t mymac[6] = {0x00,0x80,0x48,0x2d,0xf7,0x25}; // mac- static uint8_t myip[4] = {10,20,30,40}; // ip- 10.20.30.40 #define MYPORT 5555 #define BUFFER_SIZE 500 static uint8_t buf[BUFFER_SIZE+1]; static char number[7]; const byte clockPin = 7; // const byte latchPin = 8; // const byte dataPin = 9; // const byte NumRegs = 4; // const byte NumCols=10; const byte NumRows=16; // - , // // 4 , , // // () 1 32 // 26 (10+16) - byte Col_bits[NumCols] = {3,5,7,11,13,15,19,21,23,27}; // // , .. 1- // 3 .. byte Row_bits[NumRows] = {32,30,28,26,24,22,20,18,16,14,12,10,8,6,4,2}; // // byte Regs[NumRegs]; int reg_n, bit_n, in_r, in_c; // , . // 2! ;) // - byte matrix[NumRows][NumCols]={{1,0,1,0,0,0,1,1,1,1}, {1,0,1,0,0,0,0,0,0,1}, {1,0,1,0,0,0,0,0,0,1}, {1,0,1,0,0,0,0,0,1,0}, {1,0,1,0,0,0,0,0,1,0}, {1,0,1,1,0,0,0,0,1,0}, {1,0,1,0,1,0,0,1,0,0}, {1,0,1,0,1,0,0,1,0,0}, {1,0,1,0,1,0,0,1,0,0}, {1,0,1,0,1,0,1,0,0,0}, {1,0,1,0,1,0,1,0,0,0}, {1,0,1,1,0,0,1,1,1,1}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}}; EtherShield es=EtherShield(); void setup() { pinMode(latchPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(clockPin, OUTPUT); es.ES_enc28j60Init(mymac); // es.ES_init_ip_arp_udp_tcp(mymac,myip, MYPORT); // } void loop() { uint16_t plen, dat_p, ptr; while(1) { burn_matrix(); // // ( ). // , // - // - read packet, handle ping and wait for a tcp packet: dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf)); /* dat_p will be unequal to zero if there is a valid request */ if(dat_p == 0) { // no request continue; } // :) // "IbZ " if (strncmp("IbZ ",(char *)&(buf[dat_p]),4)==0) { // 4- ptr = dat_p+4; for(in_r=0; in_r < NumRows; in_r++) { for(in_c=0; in_c < NumCols; in_c++) { matrix[in_r][in_c] = 0; // ( , ;) ) } } // - - // , - 0 while(buf[ptr] != 0) { in_r = (buf[ptr]-1) % 16; in_c = (buf[ptr]-1) / 16; matrix[in_r][in_c] = 1; // ptr++; } } } } void burn_matrix() { // - 1- , , // 2- , 10- for(int c = 0; c < NumCols; c++) { for(int i = 0; i < NumRegs; i++) { Regs[i]=255; } reg_n = (Col_bits[c]-1) / 8; bit_n = (Col_bits[c]-1) % 8; bitWrite(Regs[reg_n], bit_n, 0); for(int r = 0; r < NumRows; r++) { reg_n = (Row_bits[r]-1) / 8; bit_n = (Row_bits[r]-1) % 8; bitWrite(Regs[reg_n], bit_n, matrix[r][c]); } registerWrite(); delay(1); } } // - void registerWrite() { digitalWrite(latchPin, LOW); for(int cur_reg = NumRegs-1; cur_reg >= 0; cur_reg-- ) { shiftOut(dataPin, clockPin, MSBFIRST, Regs[cur_reg]); } digitalWrite(latchPin, HIGH); }


The algorithm is simple: if the channel stops working, you can immediately see that the LED starts to burn and does not go out.
When the channel is checked, the LED is on, if everything is good, the LED will go out, i.e. it is visible as the script checking channels runs. It runs on the monitoring server once every half hour (each channel takes a little more than 8 seconds), the private federal user is checked separately and is not displayed here - in the plans (unfortunately, the truth is probably already impossible :() to make a matrix for a larger number of LEDs, to run several servers monitoring (parallel process so that all channels are checked every 5-10 minutes).

Here is a short video:



Well, as is customary, the approximate cost of the main materials used (basically everything is bought on ebay / Chinese shops):
Breadboard Prototype PCB Print Circuit Board 18 x 30~ $ 4
160 3mm green LEDsless than $ 5 can be found
Arduino~ $ 16
ENC28J60 Ethernet Shield for Arduino Duemilanove / Uno~ $ 16
4 registers 74HC595~ $ 3
Total~ $ 45-50

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


All Articles