Hockey Goal Light

I am currently working on a project to incorporate the Spark core with a Goal Light(pictured below). With some help obtained from these forums I already have the light functioning with the Spark Core. My next step is to have the Spark core trigger light when my favorite team(Boston Bruins) scores a goal.

Initially I found this. Someone had done something similar with Arduino and was nice enough to put it on github. I believe that this version is a little more complicated than it needs to be for my application.

That version does use JSON from this page: Live Scores

Jesse Scott, author of the above example had very useful code in his “parseTeam.pde” to accomplish what I need. I just need some help from the community to complete the code.

I plan to post pictures and a wiring diagram upon completion of the project, when I put everything together.

Thanks to @kennethlimcp for helping with some initial brainstorming.

Web Site

The live.nhle.com page referenced above is constantly updated with current information. This is what I would like to accomplish:

  1. Check the page for “LIVE” games.
  2. Does the “LIVE” game feature the desired Team(favTeam).
  3. If (favTeam) is “LIVE” then read whether or not it is atn or htn (Away Team Name or Home Team Name)
  4. Detect score value when game becomes live, then trigger light upon any increase. The closer to the actual goal the better.

This is an example of the JSON from a live game.

{“id”:2013030114,“gs”:3,“ts”:“03:49 1st”,“tsc”:“progress”,“bs”:“LIVE”,“bsc”:“progress”,“atn”:“Boston”,“atv”:“bruins”,“ats”:“0”,“atc”:“progress”,“htn”:“Detroit”,“htv”:“redwings”,“hts”:“1”,“htc”:“progress”,“pl”:true,“rl”:false,“vl”:false,“gcl”:true,“gcll”:true,“ustv”:“NBCSN”,“catv”:“RDS,TSN”}

JesseScott uses code like this to define sections:

sections = split(_gameDayStats, ‘:’);

// Message
bParsing = true;

// Get Line With Score
for(int i = 0; i < sections.length; i++) {
// Print
if(verbose) println(sections[i]);

  // Set Line With Score
  if(sections[i].contains(favTeam)) {
     // Set Line With Score
     scoreLine = sections[i+2];
     // Home
     if(sections[i].contains("htv")) {
       otherTeam = sections[i-4];
     }
     // Away
     else if(sections[i].contains("atv")) {
       otherTeam = sections[i+4];
     }
     // Parse
     score = split(scoreLine, ',');
  }

Eventually I’d like to add an LCD screen, so defining integers for home and away teams, scores, time left, and current period would be helpful.

1 Like

I’ll chip in a little more for anyone who can help get this running faster:

  1. we can use the JSON parser @peekay123 has ported to read the data

  2. they are using JSONp while is calling for a remote site and there’s and additional function () around the {json data} like function ({json data})

So someone with more experience can help see if the parser can handle this. Honestly this is not my area of expertise.

I guess it won’t be too hard since we will use a TCPclient to read the values and parse the data, read what we want and trigger the Light!

Got @TheRick to open a thread cos the community can help make this work faster than I do :slight_smile:

kennethlimcp, there is actually a higher level json parser that uses jsnm that was used in the openweather code. I have it here on my github. I used it to parse both current and forecasted weather. I can easily be used in this case. I will look at how he parses the json and come up with the correct code. If you can’t wait, look at the openweather library for inspiration. :smile:

I’ll wait for you and just enjoy my breakfast :smiley:

TheRick, can I ask how you got that specific JSON response or is it just a part of the larger response?

It's a huge dataset from:

http://live.nhle.com/GameData/RegularSeasonScoreboardv3.jsonp

It’s from http://live.nhle.com/GameData/RegularSeasonScoreboardv3.jsonp?loadScoreboard=?

The content varies. For instance I noticed it has the information for all games up until 4/27 currently. One complication that may arise is that It currently shows JSON with the final score from the Bruins game from Thursday, as well as the upcoming game for tomorrow. You’ll notice that the “bs” section on one game is “final OT” while the other is “3 PM”(game time EST). That value shows as “Live” when a game is in progress.

I suppose that can be resolved by first looking for games with the current date. Perhaps checking each day for “Boston” games, then begin parsing on a frequent interval beginning at the scheduled start time…

Yikes! That page is 3627 characters long! This is way too large to buffer. There has got to be a better way to get the scores down to a smaller JSON response!

Ok, just realized that the sketch is written in PROCESSING running on a PC connected to an Arduino UNO running Firmata (to control the light).

We need to look for an alternate game score site that allows better JSON querying.

UPDATE: may be able to use http://sports.espn.go.com/nhl/bottomline/scores if I can figure out the data. Here is the response with the %20 converted to spaces:

&nhl_s_delay=120&nhl_s_stamp=0425182413&nhl_s_left1=NY Rangers 1 Philadelphia 2 (11:18 IN 3RD)&nhl_s_right1_1=LAST GOAL: (PP) Voracek (24)&nhl_s_right1_count=1&nhl_s_url1=http://sports.espn.go.com/nhl/scoring?gameId=400552600&nhl_s_left2=Chicago 1 St. Louis 1 (8:11 IN 2ND)&nhl_s_right2_1=LAST GOAL: Oshie (22)&nhl_s_right2_count=1&nhl_s_url2=http://sports.espn.go.com/nhl/scoring?gameId=400552552&nhl_s_left3=Dallas at Anaheim (10:30 PM ET)&nhl_s_right3_1=R. Getzlaf 87 pts, 31 goals&nhl_s_right3_2=J. Hiller .911 sv%25, 2.48 gaa&nhl_s_right3_3=T. Seguin 84 pts, 37 goals&nhl_s_right3_4=K. Lehtonen .919 sv%25, 2.41 gaa&nhl_s_right3_count=4&nhl_s_url3=espn.com

I think this might help. I’m just working my way through it right now. The site explains(amongst other things) the various way to call for JSON data via different URLs. Like I said, I just began reading, but for example the following returns a schedule based on the date:

http://live.nhle.com/GameData/GCScoreboard/2014-04-26.jsonp

Would it be possible to use that page to parse the Game ID each day? Then we could use this:

Structure: “http://live.nhle.com/GameData/” + Year (ex 20132014) + “/” + Gameid (ex 2013020821) + “/gc/” + Data Wanted (gcsb, gcbx etc…) + “.jsonp”

TheRick, so now we are down to 1264 bytes of data which may be feasible. So if I specify an ID from today's games using http://live.nhle.com/GameData/20132014/2013030165/gc/gcsb.jsonp, I get this:

GCSB.load({"gid":2013030165,"bc":["US","CA"],"gf":2,"p":3,"sr":21,"cr":true,"a":{"id":16,"ab":"CHI","oi":[50,4,81,27,28,19],"pa":[{"g":1,"s":9},{"g":1,"s":11},{"g":0,"s":7}],"tot":{"g":2,"s":27}},"h":{"id":19,"ab":"STL","oi":[19,39,74,27,17,20],"pa":[{"g":0,"s":6},{"g":1,"s":13},{"g":1,"s":7}],"tot":{"g":2,"s":26}},"le":{"id":758,"p":3,"sip":1165,"type":516,"dc":608,"desc":"3/19:25 - Stoppage (Goalie Stopped)"}})

I have NO idea what "data wanted" of "gcsb" means and I have not ideat how to look at that response! There's a score in there????

For CHI in that example:

{“g”:1,“s”:9},{“g”:1,“s”:11},{“g”:0,“s”:7}],“tot”:{“g”:2,“s”:27}}

Each bracket represents goals and shots for each period, with the “tot” being the total. The g value in the total box would be the way to go. Games start with only one “tot” bracket, and a new bracket is created for each new period, including overtimes.

For example this is from a game that has yet to start:

GCSB.load({“gid”:2013030115,“bc”:[“US”,“CA”],“gf”:1,“p”:1,“sr”:1200,“cr”:false,“a”:{“id”:17,“ab”:“DET”,“tot”:{“g”:0,“s”:0}},“h”:{“id”:6,“ab”:“BOS”,“tot”:{“g”:0,“s”:0}}})

@peekay123 We’re currently in the playoffs, so of course less games mean less characters for now. Is that something that could cause an issue during regular season? I am curious is parsing the data elsewhere is a better idea, then returning only relavant data to a different source for the core to reference…

You could probably still parse it on the Core, but it would be pretty tedious. I’m not 100% sure on how TCPClient buffers, but I think it’s limited to 1000 bytes. I just did a tcpdump to see how large the returning packets are, and it looks like the actual JSON data comes back in 3 packets of 1460 bytes, 1460 bytes, and 717 bytes (as of 12:02 AM Eastern). I know the typical max packet size you will see on the Internet is just under 1500 bytes which may be too much for the Core as is. I’m wondering if @zachary, @satishgn, or someone from the Spark team can comment on that.

In the short term, it may be easier to parse it through some middle-man and have your Core grab only the relevant data from there. It’d be a piece of cake in one of the modern web programming languages (PHP, Ruby, Python, C#, ASP.Net, etc). Heck, if you’re going to beat the Red Wings, I’m all for helping out if you need some place to host a middle-man script in PHP. I don’t have a server with any of those other languages readily available, though.

1 Like

TheRick, if it works or not will come down to available RAM I suspect. Can you detail the process for each day detailing the steps for getting what you need? In the meantime, I have to get some sleep! :smile:

1 Like

Same here. Neither one of our teams made the playoffs this year. :frowning:

I am not sure the total length matters too much as long as you servicing the TCP stream with some speed and not trying to buffer the entire thing. The TCP ACKs for the subsequent packets just aren’t sent until you pick up the current packet. If you are too slow, the connection could timeout, but that has not been a problem for me.

For instance, I can read a Yahoo weather RSS feed, parsing it on the fly as I do TCPClient.read() and the total page length is over 2700 bytes. If you are trying to use the JSON parsers that work on the entire JSON as a string, you don’t have a lot of options, but parsing it yourself a byte at a time or a small buffer at a time (64 chars or so) could be done.

1 Like

If the Core can handle chunking the payload up a little, using the String class wouldn’t be too terrible to parse with. String.indexOf() could probably help make (relatively) quick work of it instead of trying a character-by-character parser (which I’ve done a few of those before, ugh).

Yup, chunking may be the most feasible way though I suspect with larger chuncks… It becomes a bigger problem when the parsing crosses chunk boundaries. From what I can see, each “game” is represented by a JSON object of 320 bytes and the preamble to the entire response is 21 bytes. So those bytes are received and tossed then 320 bytes chunks can be received and parsed using either JSON or String to get the game “id” of the target team. The response using the game id is 417 bytes long and the first 80 bytes are not necessary. The JSON objects of interest are 114 bytes in size.

SO, all this to say that a buffer of 500-600 bytes would be fine for processing the response. Because JSON can only parse “complete” objects, the String approach is best.

All that is a bit over my head. I have a message out to someone with more knowledge about obtaining different data from the live.nhle.com site. Hopefully he can shed light on an easier way to obtain game data for a specific team or game.

1 Like

I’m actually surprised that I found a thread where someone has a similar idea. I would like to actually use the Spark Core obtain live scores for my favorite hockey team (Flyers). I’m actually running into a similar issue where it’s difficult to find free live scores that are easy to parse. I know XML which is what I’ve been looking for (from what I’ve read, JSON isn’t bad).

I haven’t played with the S-Core in quite a while. But this may motivate me to do something with it and my Arduino.

1 Like