Starting Electronics needs your help! Please make a donation to help cover our hosting and other costs. Click the donate button to send a donation of any amount.
Created on: 2 June 2015
In this project, an Arduino and Ethernet shield are used to get live cricket scores from the Internet. The same technique could be used to get sport scores for other sports.
The Arduino sketch configures the Arduino as an Ethernet client that periodically requests the scores from the cricbuzz.com website. The scores are received as an XML file which the Arduino parses to extract the score information.
The extracted scores and game information are displayed in the Arduino IDE serial monitor window.
This project can be used as a basis for getting started with similar projects for other sports scores and results. The code can also be adapted to support other displays such as an LCD.
The video below shows the Arduino fetching the sports scores and displaying them in the Serial Monitor window:
Can't see the video? View on YouTube →
Update
See the improved cricket score ticker that uses an SD card to first save the entire XML file before parsing it.
The code below can be copied and pasted to the Arduino IDE and then loaded to the Arduino.
An Arduino and Ethernet shield or Arduino with built-in Ethernet is needed. The SD card is not used.
After loading the sketch to the Arduino, open the Arduino IDE Serial Monitor window to view the scores. Make sure that the baud rate is set to 115200 as shown in the video above.
Be sure to read the text below the sketch to understand the limitations of the sketch and for an explanation on how the code works.
Use the form below to configure the sketch to suit your network and desired settings.
Change these settings to suit your network and Arduino board. After making changes, click the Generate Code button to apply the changes to the Arduino sketch below. Click the Select Code button to select the code for copying.
/* Gets the cricket score from synd.cricbuzz.com/j2me/1.0/livematches.xml * Displays the score in the Serial Monitor window * * References: Arduino Examples from IDE * - File --> Examples --> Ethernet --> WebClient * - File --> Examples --> Ethernet --> WebClientRepeating * * More information at: * http://startingelectronics.org/software/arduino/live-cricket-score/ * * Author: W.A. Smith Date: 2 June 2015 */ #include <SPI.h> #include <Ethernet.h> // score refresh period in seconds #define REFRESH_PERIOD_SEC 15L // size of parse buffer in bytes #define BUF_PARSE_SZ 50 byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; char server[] = "synd.cricbuzz.com"; IPAddress ip(192, 168, 0, 50); EthernetClient client; void setup() { // disable the SD card by switching pin 4 high pinMode(4, OUTPUT); digitalWrite(4, HIGH); Serial.begin(115200); // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); // no point in carrying on, so do nothing forevermore: // try to congifure using IP address instead of DHCP: Ethernet.begin(mac, ip); } // give the Ethernet shield a second to initialize: delay(1000); } void loop() { static char pars_buffer[BUF_PARSE_SZ] = {0}; static int pars_buf_idx = 0; httpRequest(); // if there are incoming bytes available // from the server, read them and print them: if (client.available()) { char c = client.read(); pars_buffer[pars_buf_idx] = c; pars_buf_idx++; if (ParseXMLBuffer(pars_buffer) == true) { // reset the buffer; pars_buf_idx = 0; pars_buffer[0] = 0; } // last char in parse buffer is always null terminator 0 if (pars_buf_idx >= (BUF_PARSE_SZ - 1)) { LeftShiftBuffer(pars_buffer, (BUF_PARSE_SZ - 1)); pars_buf_idx = BUF_PARSE_SZ - 2; } } } // this method makes a HTTP connection to the server: void httpRequest() { static unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds static const unsigned long postingInterval = REFRESH_PERIOD_SEC * 1000L; // delay between updates, in milliseconds // the "L" is needed to use long type numbers // if ten seconds have passed since your last connection, // then connect again and send data: if (millis() - lastConnectionTime > postingInterval) { // close any connection before send a new request. // This will free the socket on the WiFi shield client.stop(); if (client.connect(server, 80)) { Serial.println("\r\nconnected"); // Make a HTTP request: client.println("GET /j2me/1.0/livematches.xml HTTP/1.1"); client.println("Host: synd.cricbuzz.com"); client.println("Connection: close"); client.println(); // note the time that the connection was made: lastConnectionTime = millis(); } else { // didn't get a connection to the server: Serial.println("connection failed"); } } } boolean ParseXMLBuffer(char *str) { int reset_buffer = false; static int state = 0; static bool result = false; // match has a result switch (state) { case 0: // start of match information <match> if (strncmp(str, "<match", 6) == 0) { state++; Serial.println("\r\n"); } break; case 1: if (PrintXMLNameValue("Match Type: ", "type", str)) { Serial.println(); state++; } break; case 2: if (PrintXMLNameValue("Match Series: ", "srs", str)) { Serial.println(); state++; } break; case 3: if (PrintXMLNameValue("Match Description: ", "mchDesc", str)) { Serial.println(); state++; } break; case 4: if (PrintXMLNameValue("Match Number: ", "mnum", str)) { Serial.println(); state++; } break; case 5: // get match status if (strncmp(str, "mchState=\"", 10) == 0) { if (strncmp(&str[10], "Result", 6) == 0) { result = true; } else { result = false; } state++; } break; case 6: if (PrintXMLNameValue("Match Status: ", "status", str)) { Serial.println(); state++; } break; case 7: if (result == false) { // match does not have a result, so get the details if (GetInningsDetail(str) == true) { state++; } } else { state++; } break; case 8: // end of match information </match> if (strncmp(str, "</match>", 8) == 0) { Serial.println("\r\n"); state = 0; result = false; } break; default: state = 0; result = false; reset_buffer = true; break; } return reset_buffer; } bool GetInningsDetail(char *str_xml) { static int innings_state = 0; bool done = false; switch (innings_state) { case 0: if (PrintXMLNameValue("Number of overs: ", "noofovers", str_xml)) { Serial.println(); innings_state++; } break; case 1: if (PrintXMLNameValue("Required run rate: ", "rrr", str_xml)) { Serial.println(); innings_state++; } break; case 2: if (PrintXMLNameValue("Current run rate: ", "crr", str_xml)) { Serial.println(); innings_state++; } break; case 3: if (PrintXMLNameValue("Team: ", "sName", str_xml)) { Serial.print(" "); innings_state++; } else if (strncmp(str_xml, "</mscr>", 7) == 0) { // end of score data innings_state = 7; } break; case 4: if (PrintXMLNameValue("-- Runs: ", "r", str_xml)) { Serial.print(" "); innings_state++; } else if (strncmp(str_xml, "</mscr>", 7) == 0) { Serial.println(" -- "); // end of score data innings_state = 7; } break; case 5: if (PrintXMLNameValue("-- Overs: ", "ovrs", str_xml)) { Serial.print(" "); innings_state++; } break; case 6: if (PrintXMLNameValue("-- Wickets: ", "wkts", str_xml)) { Serial.println(""); innings_state = 3; // check other teams score } break; case 7: done = true; innings_state = 0; break; default: done = true; innings_state = 0; break; } return done; } // print the value from the XML name str_xml_name found in str_xml // label - title of parameter(value) displayed on screen // str_xml_name - name of the XML name/value pair // str_xml - XML string to search for the value of the name/value pair bool PrintXMLNameValue(char *label, char *str_xml_name, char *str_xml) { char temp_str[35] = {0}; int str_length = 0; bool found_name = false; strcpy(temp_str, str_xml_name); // string to search for is in the format name=", so add =" to the end of name strcat(temp_str, "=\""); str_length = strlen(temp_str); if (strncmp(str_xml, temp_str, str_length) == 0) { Serial.print(label); PrintUntilCloseQuote(&str_xml[str_length]); found_name = true; } return found_name; } // print characters from string str until a quote " is found or end of string void PrintUntilCloseQuote(char *str) { int i = 0; do { Serial.print(str[i]); i++; } while ((str[i] != '\"') && (str[i] != 0)); } // shift contents of buffer buf[] one byte to the left void LeftShiftBuffer(char *buf, int buf_sz) { for (int i = 0; i < buf_sz; i++) { buf[i] = buf[i + 1]; } }
You can help the Starting Electronics website by making a donation:
Any donation is much appreciated and used to pay the running costs of this website. Click the button below to make a donation.
Firstly note that this is a first attempt at parsing the XML cricket score file and uses a weak method of parsing the file. This is partly due to the memory limitations of the smaller Arduinos.
The buffering and parsing methods in this code are not efficient and can be improved – hopefully in a future project that will improve on this current project.
Because of the weak parsing techniques used in the code, it is possible that the code will break if anything unexpected is encountered in the XML file. This includes changing the order in which name/value pairs appear in the XML.
This project is really a quick sketch to get the cricket score displayed and to serve as a starting point for future better projects.
After connecting to the XML feed, the Arduino puts bytes received from the feed into the array / buffer pars_buffer[] one byte at a time. When the buffer is full, the entire buffer is left-shifted and each new byte is added to the end of the buffer after shifting.
The buffer is a "window" of the incoming data that contains a portion of the incoming data limited by the size of the buffer. This buffer is parsed "on the fly" by the Arduino without saving the entire incoming XML file to memory.
After a new byte is placed in the buffer, the buffer is checked to see if it contains the desired XML tag or name of a name/value pair. This is done by the ParseXMLBuffer() function.
The ParseXMLBuffer() function looks for for various tags and names in sequence in a switch statement. For example, it first looks for the opening <match tag, ignoring all other text until this tag is found.
After finding the opening match tag, it will then look for the type name and get and print the value of the match type using the PrintXMLNameValue() function e.g. if the name value pair is type="TEST" then the value TEST (for test match) is extracted and displayed.
Here we can see one of the weaknesses of the code in that it reads name/value pairs in the expected order. If any name/value pair order is changed the code will break.
Some matches will be finished and will have a result. If the match result is available, then the data for the match will not contain information such as the number of overs and the current run rate. The result variable in the ParseXMLBuffer() function is used to flag matches that have a result so that the code does not try to extract data that does not exist for a finished match.
Only if the match does not have a result, will the function GetInningsDetail() be called that gets further live information about the match that is currently being played.
Thanks to John for asking a question on the Starting Electronics blog about how to display the live cricket score which got this project started.
The client connection and resource request part of this project is based on two examples from the Arduino IDE built-in examples. These are found in the IDE under:
The pages for these two examples can be found on the Arduino website at:
The live cricket XML feed is read from https://www.cricbuzz.com/cricket-match/live-scores
As an Amazon Associate I earn from qualifying purchases: