To solve this problem, it’s necessary to understand the existing code and its intended structure. It cannot be solved by guessing. Also keep in mind that errors are reported where they are detected, which is not necessarily exactly where the problem is.
Could you please help me understand how I find where the problem is.
Assuming that you understand the reason why there are indents in the source code at all, and what they mean in general, there is nothing more I can possibly explain. The rest is a matter of problem solving skills, not education.
That’s the problem, I didn’t write the original code, and I have no idea why they’re there or what they mean.
Oh, I see. The tutorial isn’t about teaching you how to write code at all; it’s about how to set up some hardware and make it run the code that is given to you.
I think you had better talk to the authors about this.
I would but I can’t as the author hasn’t been around for a long time.
This is a not for profit project to build scoreboards.
All of it is in html.
Then someone who’s no longer around wrote this python integration so that the official ECB cricket scoring app could control the scoreboard.
Then the original html project was enhanced to add a spectator scoreboard which uses the html.
But the ECB app works differently so when using that the spectator board doesn’t work.
The html creates a json file which the spectator board pulls.
All I am trying to achieve is to enhance the python script to produce the json file.,but I have no idea how, hence my post, hoping someone can help me.
Ok. Post the current state of the code, and the current error message.
We need to see both. Particularly, if you change the code then the line
numbers will change (if you insert or remove lines), so we need the code
to match up the error message to the code.
Indentation is how Python expresses the control flow. If we have an
if-statement to do one set of commands (or, optionally, an alternative)
then the indentation groups the commands. Example from your script:
if ScoreType == "OVB":
if ScoreData.find(".") == -1:
Overs = ScoreData.rjust(2,"-")
else:
Overs = ScoreData.split(".",1)[0].rjust(2,"-")
elif ScoreType == "B1S":
BatA = ScoreData.rjust(3,"-")
This is part of the if-statement which seems to receive a bluetooth
message and update the scoreboard connected to your /dev/ttyACM0
serial device. If the message type is "OVB"
it does the entire
if-else
pair underneath that test. Otherwise, if the message type is
"B1S"
it does the assignment statement under that. And so on for other
message types.
Everything between the top if
and the next elif
is indented to show
that it is all a group to be done if the top if
test is true (an
"OVB"
message). Similarly, inside that group (the inner if-else
) the
true/false branches are themselves indented.
Python uses indents to define what’s “inside” (indented further) or not.
Everything one level inside needs the same amount of extra indentation.
So above, the first if
and the elif
need the same indentation.
Inside the “true” part of the first if
, the inner if
and else
need
the same indent as each other.
Here’s a while loop:
print("before the loop")
while some_test_function():
print(1)
do_something()
print(2)
print("after the loop")
The first print()
, the while
and the last print()
all need the
same indentation.
The things to happen inside the loop (a print()
, another function
call, and another print()
) need need the same indentation, which needs
to be more than that of the while
because they’re inside the
while
.
See that there’s no “end of the loop body” marker? Python knows that the
final print()
is not part of the loop body because it is back at the
same indent as the while
statement itself.
If there are changes of indent but no associated control structure like
an if
or while
to cause the new indent, that’s an indentation error.
Example:
while some_test_function():
print(1)
do_something()
print(2)
The last print(2)
above is incorrectly indented.
Syntax errors are more to do with incorrect or incomplete structure.
Here’s an if-statement:
if ScoreData.find(".") == -1:
Overs = ScoreData.rjust(2,"-")
else:
Overs = ScoreData.split(".",1)[0].rjust(2,"-")
The else:
is syntacticly correct because it is parrt of the preceeding
if
. But this:
else:
Overs = ScoreData.split(".",1)[0].rjust(2,"-")
on its own would cause a SyntaxError
because there’s no preceeding
if
.
Thank you for such a comprehensive reply, a lot for me to digest there.
I built the scoreboard cabinet, soldered all the chips & did all the wiring, and enhanced the html interfaces to include lots of extra elements. The final link to make it as I want is this Scorer App integration for the spectator board. I’m sorry that I’m so poor at this aspect & I truly appreciate your efforts to help & educate me.
Here are the current error messages:
pi@scoreboard:~ $ cd /usr/local/bin/scoreboard
pi@scoreboard:/usr/local/bin/scoreboard $ python3 uart-peripheral.py
File "uart-peripheral.py", line 101
else:
^
SyntaxError: invalid syntax
pi@scoreboard:/usr/local/bin/scoreboard $ python uart-peripheral.py
File "uart-peripheral.py", line 101
else:
^
SyntaxError: invalid syntax
And here’s the current file:
import serial, time
import sys
import dbus, dbus.mainloop.glib
import json
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 = "---"
def update_scoreboard():
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
score_data = {
"total": BatTotal,
"wickets": Wickets,
"overs": Overs,
}
print("score_data =", score_data)
with open('score.json', 'w') as jsonf:
json.dump(score_data, jsonf)
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
update_scoreboard()
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
update_scoreboard()
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()
The error message gives you a line number, which tells you where in the file that part of the code is.
Using your text editor, can you see where line 101 is?
I can see the line that it’s complaining about, but I have no idea what to do to fix it
The lines around line 101 are these:
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
Line 101 is the else:
line. Looking at the lines above it, what do you
think might be the problem?
Remember the while-loop example in my previous post. Python does not end
identify the end of the loop body with a special marker, it sees a line
which is not indented into the loop body.
In the code above, the second Target =
line is not indented to be
inside the elif:
body. So the if-statement ends there. Because the
if-statement has ended, the else:
on the following line makes no sense
because there’s no matching if
.
You want that Target =
to be indented the same as the line above it.
Thank You. I get it that indents are kind of like brackets in Excel.
Now it moans about this:
pi@scoreboard:~ $ cd /usr/local/bin/scoreboard
pi@scoreboard:/usr/local/bin/scoreboard $ python uart-peripheral.py
File "uart-peripheral.py", line 106
if UpdateScoreboard:
^
SyntaxError: invalid syntax
pi@scoreboard:/usr/local/bin/scoreboard $ python3 uart-peripheral.py
File "uart-peripheral.py", line 106
if UpdateScoreboard:
^
SyntaxError: invalid syntax
Current py file:
import serial, time
import sys
import dbus, dbus.mainloop.glib
import json
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 = "---"
def update_scoreboard():
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
score_data = {
"total": BatTotal,
"wickets": Wickets,
"overs": Overs,
}
print("score_data =", score_data)
with open('score.json', 'w') as jsonf:
json.dump(score_data, jsonf)
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
update_scoreboard()
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
update_scoreboard()
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()
I wonder whether it might be time to give up, I’m taking up too much of your time.
I would still like to achieve this but you must be getting very frustrated with me for which I can only apologise
Thank You. I get it that indents are kind of like brackets in Excel.
Yes.
Now it moans about this:
pi@scoreboard:~ $ cd /usr/local/bin/scoreboard pi@scoreboard:/usr/local/bin/scoreboard $ python uart-peripheral.py File "uart-peripheral.py", line 106 if UpdateScoreboard: ^ SyntaxError: invalid syntax
This is very similar. See the indent of the if UpdateScoreboard:
? It
is not indented the same as the rest of the code in the
try:
…except
. Instead it is indented like the except
below it.
The rule’s the same: everything inside a block must have the same
indent. So they try:
is indented a certain amount. Everything inside
it should be indented more, and the same amount, until the except
which ends the try
clause.
Each level of control statement such a try
…except
,
if
…elif
…else
, while
and for
surrounds some code. The
surrounded code must be indented, and all to the same indent.
The reason Python’s so picky about the exact indent is that a change of
indent means you’ve entered some control statement (while
etc) if the
indent gets bigger or left the statement if the indent gets smaller.
If the new indent does not match a previous indent it is taken as a sign
that something’s wrong.
Progress, both in the python & my understanding (a bit!)
pi@scoreboard:/usr/local/bin/scoreboard $ python uart-peripheral.py
4,--0,0,-0,---#
/dev/ttyACM0 connected!
Data Sent: 4,--0,0,-0,---#
('score_data =', {'total': '--0', 'overs': '-0', 'target': '---', 'wickets': '0'})
Traceback (most recent call last):
File "uart-peripheral.py", line 64, in <module>
update_scoreboard()
File "uart-peripheral.py", line 49, in update_scoreboard
with open('score.json', 'w') as jsonf:
IOError: [Errno 13] Permission denied: 'score.json'
pi@scoreboard:/usr/local/bin/scoreboard $ python3 uart-peripheral.py
4,--0,0,-0,---#
/dev/ttyACM0 connected!
Data Sent: 4,--0,0,-0,---#
score_data = {'total': '--0', 'wickets': '0', 'overs': '-0', 'target': '---'}
Traceback (most recent call last):
File "uart-peripheral.py", line 64, in <module>
update_scoreboard()
File "uart-peripheral.py", line 49, in update_scoreboard
with open('score.json', 'w') as jsonf:
PermissionError: [Errno 13] Permission denied: 'score.json'
So…
If I follow your instructions above about the permissions to the json file, will that mess up the permissions that the web page has to that file? Maybe I could call this output scorePCS.json & just create a separate spectator board that looks at that file, assuming the permissions relate to the file & not the folder.
Secondly, the json output from the python has an extra space in it just after the colon. Is there any way to remove it?
HTML: {“total”:“–0”,“wickets”:“0”,“overs”:“-0”, etc
Python {‘total’: ‘–0’, ‘overs’: ‘-0’, etc
There’s no real need to try both python
and python3
. This is
permissions which are entire to do with the file an the OS. So:
pi@scoreboard:/usr/local/bin/scoreboard $ python uart-peripheral.py
4,--0,0,-0,---#
/dev/ttyACM0 connected!
Data Sent: 4,--0,0,-0,---#
('score_data =', {'total': '--0', 'overs': '-0', 'target': '---', 'wickets': '0'})
Traceback (most recent call last):
File "uart-peripheral.py", line 64, in <module>
update_scoreboard()
File "uart-peripheral.py", line 49, in update_scoreboard
with open('score.json', 'w') as jsonf:
IOError: [Errno 13] Permission denied: 'score.json'
You’re standing in the /usr/local/bin/scoreboard
directory, so writing
to 'score.json'
tries to make a file in that directory. Can you show
up the output of the command ls -la
please?
I would infer that either you lack write permission to that directory,
or the score.json
file exists and you don’t have write permission to
it.
For the exercise we could make the file here. In fact, maybe that would
be a good thing, on reflection.
So…
If I follow your instructions above about the permissions to the json file, will that mess up the permissions that the web page has to that file?
Not, it should be ok. That was the purpose of the chmod a+r
command:
to give all users read access to the file.
The objective is that you (the pi
user) should have write access to
the file so that you can update it, and that the user running the web
server has read access to the file so that it can serve it to a web
user. So the ritual above (run as root
, who can do anything) makes the
file, gives ownership to you, and public read access (since I assume the
scores are not secret).
Maybe I could call this output scorePCS.json & just create a separate
spectator board that looks at that file, assuming the permissions
relate to the file & not the folder.
In principle it could be either. The ls -la
command requested above
should tell us.
So I think we should:
- do an
ls -la
to see what the state of the/usr/local/bin/scoreboard
directory is - fix up the
score.json
file there so that the script can write to it - we’ll just put a symlink over in
/var/www/html
which references the original in/usr/local/bin/scoreboard
Secondly, the json output from the python has an extra space in it just after the colon. Is there any way to remove it?
HTML: {“total”:“–0”,“wickets”:“0”,“overs”:“-0”, etc
Python {‘total’: ‘–0’, ‘overs’: ‘-0’, etc
You don’t need to. JSON allows white space (spaces etc) between the
values and punctuation. It’s common to see this stuff spread out over
several lines in a JSON file, a lot like how we defined data
in the
Python script.
However, if you want to have no spaces that’s perfectly fine and doable.
Just change the line containing json.dump(...)
to be like this:
json.dump(score_data, jsonf, separators=(',', ':'))
which will write “,
” instead of ",
" and “:
” instead of ":
".
Adjust to your liking.
The web page stuff should not care either way - they’ll be using some
standard JSON parsing library to load this stuff up, and it should cope
regardless.
The docs for the json.dump
function are here:
if you want the gnarly details.
If you want the even more gnarly details of the JSON spec itself, that
is here: RFC 7159 - The JavaScript Object Notation (JSON) Data Interchange Format
Indeed, normally one would need to be root to write anywhere within /usr/local/bin
, yes? Probably anywhere in the entire /usr
hierarchy, even, I think.
Well, in these modern times? Not necessarily.
Anyway, the scoreboard script is clearly in a subdirectory of
/usr/local/bin
and the pi
user presumably has write permission to
it. We’ll know soon from the ls
output.
I expect /usr
to have things owned by by root
on the whole, but
places like /usr/local
can often contain things writable by other
users. For example, perhaps people on a hypothetical sysadmins
group
can put things in /usr/local/bin
etc.
Kits like homebrew often expect to install into a tree in /usr/local
running as the user. Me, I go the whole hog, wrapping the
brew
command in this script which has my homebrew install in
~/var/homebrew
:
Anyway, the OP’s script is, however arranged, in /usr/local
.
SUCCESS
I now have a separate file (scoreboardPCS.json) on the html folder that gets updated by the Play Cricket Scorer app.
I will have a play adding a couple of extra variables in to the output string (target, runs req etc).
I’m happy to create a separate spectator scoreboard html page.
The reason for keeping it separate is that there are variables sent by the html that aren’t available in the PCS app, for example batanumber
But I should be able to take it from here, thank you so much for all your help. I’ll post if I get stuck but I’ll try first!
Glad to hear it. Good luck.