I am enhancing the cricket scoreboard project at Build Your Own Scoreboard (wordpress.com)
Normally the board is updated via a web interface which is served by a Raspberry Pi, which then outputs data to an Arduino. As part of this process the Pi saves a file called score.json which is just a string of data in this format:
{“total”:“-45”,“wickets”:“2”,“overs”:“-9”,“runsreq”:“-50”,“bata”:“–0”,“batb”:“–0”,“target”:“-90”,“batanumber”:“-1”,“batbnumber”:“-2”,“dltarget”:“000”,“lastwkt”:“-22”,“pship”:“-23”,“lastman”:“-12”}
This json file is then used by a separate html page which is a display for any spectators
However some of our matches have to be scores with an official app. So someone kindly wrote an integration script which is below.
Everything works fine EXCEPT the app integration scrpt doesn’t create the json file, so the spectator scoreboard doesn’t work
Is it possible to add code to do this into the python script?
I know some of the variables in the json file are not used in the python script, but I’m hoping that once the script forks for the variables it has I’ll be able to work out how to add others. (Or how to adjust the spectator board to just show the data that is available)
import serial, time
import sys
import dbus, dbus.mainloop.glib
from gi.repository import GLib
from example_advertisement import Advertisement
from example_advertisement import register_ad_cb, register_ad_error_cb
from example_gatt_server import Service, Characteristic
from example_gatt_server import register_app_cb, register_app_error_cb
BLUEZ_SERVICE_NAME = 'org.bluez'
DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
LE_ADVERTISING_MANAGER_IFACE = 'org.bluez.LEAdvertisingManager1'
GATT_MANAGER_IFACE = 'org.bluez.GattManager1'
GATT_CHRC_IFACE = 'org.bluez.GattCharacteristic1'
UART_SERVICE_UUID = '5a0d6a15-b664-4304-8530-3a0ec53e5bc1'
UART_RX_CHARACTERISTIC_UUID = 'df531f62-fc0b-40ce-81b2-32a6262ea440'
LOCAL_NAME = 'FoSCC-Scoreboard-TGT'
mainloop = None
# Set all the Scoreboard variables to starting positions
Wickets = "0"
Overs = "-0"
BatTotal = "--0"
BatA = "--0"
BatB = "--0"
Target = "---"
Scoreboard = "4," + BatTotal + "," + Wickets + "," + Overs + "," + Target + "#"
# Open the serial port and set the Scoreboard to starting positions
with serial.Serial("/dev/ttyACM0", 57600, timeout=1) as arduino:
# time.sleep(0.1) #wait for serial to open
if arduino.isOpen():
print("{} connected!".format(arduino.port))
arduino.write(Scoreboard.encode())
print("Data Sent: " + Scoreboard)
arduino.close
class RxCharacteristic(Characteristic):
def __init__(self, bus, index, service):
Characteristic.__init__(self, bus, index, UART_RX_CHARACTERISTIC_UUID,
['write'], service)
def WriteValue(self, value, options):
global Wickets
global Overs
global BatTotal
global BatA
global BatB
global Target
global Scoreboard
try:
WriteReturn = '{}'.format(bytearray(value).decode())
ScoreType = WriteReturn[0:3]
ScoreData = WriteReturn[3:]
#if the bluetooth data is of type OVB, B1S, B2S, BTS, FTS then we need to update the scoreboard. Other messages can be ignore.
UpdateScoreboard = True
if ScoreType == "OVB": # Let's deal with Overs Bowled!
if ScoreData.find(".") == -1: # If there's no dot because it's the end of the over, just format the number and use it
Overs = ScoreData.rjust(2,"-")
else:
Overs = ScoreData.split(".",1)[0].rjust(2,"-") # If there's a dot, take whatever's before it. Cheap way of rounding down without using a float
elif ScoreType == "B1S": # Batsman 1 score formatted with leading dashes for blanks
BatA = ScoreData.rjust(3,"-")
elif ScoreType == "B2S": # Batsman 2 score formatted with leading dashes for blanks
BatB = ScoreData.rjust(3,"-")
elif ScoreType == "BTS": # Batting Team Score
TempSplit = ScoreData.split(" &",1)[0] # Current Inning Score only (split everything before the ampersand)
BatTotal = TempSplit.split("/",1)[0].rjust(3,"-") # Everything before the dash is the score, with leading dashes for blanks
Wickets = TempSplit.split("/",1)[1].replace("10","-") # Everything after the dash is the wickets, and if it's all out (10) then make it blank because we only have 1 digit
elif ScoreType == "FTS":
TempSplit = ScoreData.split(" &",1)[0] # Current Inning Score only
Target = TempSplit.split("/",1)[0] # Everything before the dash is the score, with leading dashes for blanks
Target = str(int(Target) + 1).rjust(3,"-")
else:
print(WriteReturn + " (not used)")
#lets not send an update to the scoreboard
UpdateScoreboard = False
if UpdateScoreboard:
Scoreboard = "4," + BatTotal + "," + Wickets + "," + Overs + "," + Target + "#"
print(Scoreboard)
with serial.Serial("/dev/ttyACM0", 57600, timeout=1) as arduino:
# time.sleep(0.1) #wait for serial to open
if arduino.isOpen():
print("{} connected!".format(arduino.port))
arduino.write(Scoreboard.encode())
print("Data Sent: " + Scoreboard)
arduino.close
except:
print(sys.exc_info()[0], "occurred")
class UartService(Service):
def __init__(self, bus, index):
Service.__init__(self, bus, index, UART_SERVICE_UUID, True)
self.add_characteristic(RxCharacteristic(bus, 1, self))
class Application(dbus.service.Object):
def __init__(self, bus):
self.path = '/'
self.services = []
dbus.service.Object.__init__(self, bus, self.path)
def get_path(self):
return dbus.ObjectPath(self.path)
def add_service(self, service):
self.services.append(service)
@dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}')
def GetManagedObjects(self):
response = {}
for service in self.services:
response[service.get_path()] = service.get_properties()
chrcs = service.get_characteristics()
for chrc in chrcs:
response[chrc.get_path()] = chrc.get_properties()
return response
class UartApplication(Application):
def __init__(self, bus):
Application.__init__(self, bus)
self.add_service(UartService(bus, 0))
class UartAdvertisement(Advertisement):
def __init__(self, bus, index):
Advertisement.__init__(self, bus, index, 'peripheral')
self.add_service_uuid(UART_SERVICE_UUID)
self.add_local_name(LOCAL_NAME)
self.include_tx_power = True
def find_adapter(bus):
remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'),
DBUS_OM_IFACE)
objects = remote_om.GetManagedObjects()
for o, props in objects.items():
if LE_ADVERTISING_MANAGER_IFACE in props and GATT_MANAGER_IFACE in props:
return o
print('Skip adapter:', o)
return None
def main():
global mainloop
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()
adapter = find_adapter(bus)
if not adapter:
print('BLE adapter not found')
return
service_manager = dbus.Interface(
bus.get_object(BLUEZ_SERVICE_NAME, adapter),
GATT_MANAGER_IFACE)
ad_manager = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, adapter),
LE_ADVERTISING_MANAGER_IFACE)
app = UartApplication(bus)
adv = UartAdvertisement(bus, 0)
mainloop = GLib.MainLoop()
service_manager.RegisterApplication(app.get_path(), {},
reply_handler=register_app_cb,
error_handler=register_app_error_cb)
ad_manager.RegisterAdvertisement(adv.get_path(), {},
reply_handler=register_ad_cb,
error_handler=register_ad_error_cb)
try:
mainloop.run()
except KeyboardInterrupt:
adv.Release()
if __name__ == '__main__':
main()