Need to create a new variable based on 2 others

With a lot of help on this forum I now have a python script that takes the data from a Cricket Scoring app & outputs it to a file.
Everything works fine except the app doesn’t output a variable that I want to display.
It outputs Score (BTS) & the score at the last wicket (LWK)
I want a new variable for ‘partnership’, which would be calculated something line 'pcsPSHP = pcsBTS - pcsLWK (the pcs is to signify that the data comes from ‘play cricket scorer’)
My py code is below. I’ve tried various ways but as I’m no programmer, I can’t make it work.
Logically it should be pretty straightforward, help appreciated as always

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"
BatAscore = "--0"
BatBscore = "--0"
Target = "---"
pcsCOV = "-"
pcsOVB = "-"
pcsOVR = "-"
pcsRRQ = "-"
pcsRRR = "-"
pcsBTN = "-"
pcsFTN = "-"
pcsFTS = "-"
pcsBAN = "-"
#pcsB1S = "0"
pcsB1B = "-"
pcsB1K = "-"
pcsBBN = "-"
#pcsB2S = "0"
pcsB2B = "-"
pcsB2K = "-"
pcsF1N = "-"
pcsF1S = "-"
pcsF2N = "-"
pcsF2S = "-"
pcsLWK = "-"
pcsDLT = "-"
pcsDLP = "-" 

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,
        "OversBowled": pcsOVB,
        "OversRem": pcsOVR,
        "target": Target,
        "BatTeamName": pcsBTN,
        "RunsReq": pcsRRQ,
        "ReqRunRate": pcsRRR,
        "DLSTarget": pcsDLT,
        "DLSPar": pcsDLP,
        "Bat1Name": pcsBAN,
        "BatAscore": BatAscore,
#        "Bat1Score": pcsB1S,
        "BatABallsFaced": pcsB1B,
        "Bat1onStrike": pcsB1K,
        "Bat2Name": pcsBBN,
        "BatBscore": BatBscore,
#        "Bat2Score": pcsB2S,
        "BatBBallsFaced": pcsB2B,
        "Bat2onStrike": pcsB2K,
        "LastWicket": pcsLWK,
        "FieldTeamName": pcsFTN,
        "FieldTeamScore": pcsFTS,
        "CurrBowlName": pcsF1N,
        "CurrBowlFigs": pcsF1S,
        "CurrentOver": pcsCOV,
        "PrevBowlName": pcsF2N,
        "PrevBowlFigs": pcsF2S,
    }
    
    
    
    print("score_data =", score_data)
    ordered_score_data = dict(sorted(score_data.items()))
    with open('/var/www/html/scorePCS.json', 'w') as jsonf:
        json.dump(ordered_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 BatAscore
        global BatBscore
        global Target
        global Scoreboard
        # New code for enhanced Spectator board START
        global pcsCOV #Current Over
        global pcsOVB #Need this for spectator board in addition to 'overs' as overs is truncated but we want the scoreboard to display the decimal point
        global pcsOVR #Overs Remaining
        global pcsRRQ #Runs Required
        global pcsRRR #Run Rate Required
        global pcsBTN #Batting Team Name
        global pcsBTS #not needed as already in code
        global pcsFTN #Fielding Team Name
        global pcsFTS #Fielding Team Score (1 is added to this to generate 'target' as target is not a PCS variable
        global pcsBAN #Batsman 1 name
        #global pcsB1S #Batsman 1 score not needed as already in code
        global pcsB1B #Batsman 1 Balls Faced
        global pcsB1K #Batsman 1 on strike? (Yes - 1, No - 0)
        global pcsBBN #Batsman 2 name
        #global pcsB2S #Batsman 2 score not needed as already in code
        global pcsB2B #Batsman 2 Balls Faced
        global pcsB2K #Batsman 2 on strike? (Yes - 1, No - 0)
        global pcsF1N #Current Bowler Name
        global pcsF1S #Current Bowler Figures
        global pcsF2N #Previous Bowler Name
        global pcsF2S #Previous Bowler Figures
        global pcsLWK #Last Wicket
        global pcsDLT #Duckworth Lewis target
        global pcsDLP #Duckworth Lewis Par at end of current over
        # New code for enhanced Spectator board END
        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!
                pcsOVB = ScoreData
                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
                BatAscore = ScoreData.rjust(3,"-")
            elif ScoreType == "B2S":                                        # Batsman 2 score formatted with leading dashes for blanks
                BatBscore = 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,"-")
                
            # New code for enhanced Spectator board START
            elif ScoreType == "COV":                                        # Current Over Details
                pcsCOV = ScoreData
#            elif ScoreType == "OVB":                                        # Overs Bowled for spectator board as overs is truncated & we want the full number
#                pcsOVB = ScoreData                # MOVED TO LINE 186
            elif ScoreType == "OVR":                                        # Overs Remaining for spectator board as overs is truncated & we want the full number
                pcsOVR = ScoreData
            elif ScoreType == "RRQ":                                        # Runs Required for spectator board
                pcsRRQ = ScoreData
            elif ScoreType == "RRR":                                        # Run Rate Required for spectator board
                pcsRRR = ScoreData   
            elif ScoreType == "BTN":                                        # Batting Team Name
                pcsBTN = ScoreData
                pcsBTN = pcsBTN[:20]
            elif ScoreType == "FTN":                                        # Fielding Team Name
                pcsFTN = ScoreData
                pcsFTN = pcsFTN[:20]
            elif ScoreType == "FTS":                                        # Fielding Team Score (1 is added to this to generate 'target' as target is not a PCS variable
                pcsFTN = ScoreData
                pcsFTN = pcsFTN[:20]
            elif ScoreType == "B1N":                                        # Batsman 1 Name
                pcsBAN = ScoreData
                pcsBAN = pcsBAN[:20]
            elif ScoreType == "B1S":                                        # Batsman 1 score formatted with leading dashes for blanks
                Bat1Score = ScoreData.rjust(3,"-")
            elif ScoreType == "B1B":                                        # Batsman 1 Balls Faced
                pcsB1B = ScoreData
            elif ScoreType == "B1K":                                        # Batsman 1 On Strike?
                pcsB1K = ScoreData
            elif ScoreType == "B2N":                                        # Batsman 2 Name
                pcsBBN = ScoreData
                pcsBBN = pcsBBN[:20]
            elif ScoreType == "B2S":                                        # Batsman 1 score formatted with leading dashes for blanks
                Bat2Score = ScoreData.rjust(3,"-")
            elif ScoreType == "B2B":                                        # Batsman 2 Balls Faced
                pcsB2B = ScoreData
            elif ScoreType == "B2K":                                        # Batsman 2 On Strike?
                pcsB2K = ScoreData
            elif ScoreType == "F1N":                                        # Current Bowler Name
                pcsF1N = ScoreData
                pcsF1N = pcsF1N[:20]
            elif ScoreType == "F1S":                                        # Current Bowler  Figures
                pcsF1S = ScoreData
            elif ScoreType == "F2N":                                        # Current Bowler Name
                pcsF2N = ScoreData
                pcsF2N = pcsF2N[:20]
            elif ScoreType == "F2S":                                        # Previous Bowler Figures
                pcsF2S = ScoreData
            elif ScoreType == "LWK":                                        # Last Wicket
                pcsLWK = ScoreData
            elif ScoreType == "DLT":                                        # Duckworth Lewis Target
                pcsDLT = ScoreData
            elif ScoreType == "DLP":                                        # Duckworth Lewis Par Score at end of current over
                pcsDLP = ScoreData                
            # New code for enhanced Spectator board END  
            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()

Could you provide a minimal example? It’s not clear what all this code is doing.

Batting Team Score is extracted from the BTS sent data (which is in the format 2/245 & 0/10) by this code

            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","-")

The Last Wicket is extracted like this:

            elif ScoreType == "LWK":                                        # Last Wicket
                pcsLWK = ScoreData

So that creates the BatTotal & pcsLWK variables
(It may be necessary to create a new BatTotal2 variable withougt the preceding dashes)

What I want is a new variable PSHIP = BatTotal-pcsLWK

One way to do this is to use an f string. F strings work in many places:

print(f'{pcsBTS - pcsLWK}')

Here’s my test program which works.

pcsBTS = 10
pcsLWK = 3
print(f'pcsBTS - pcsLWK = {pcsBTS - pcsLWK}')

One thing I learned about Python is there are a bunch of ways to print variable values inside a string.

Thanks for the reply. Where would I put that in the code?

Where ever you want the data to be transmitted or displayed. It looks like you are sending data over a serial port and I don’t know much about that.

EDIT: It looks like you are storing the data in a JSON file which comes form your dictionary score_data, so after pcsPSHP is calculated, update that entry in your dictionary before the JSON file is written from your dict.

But I gave you the syntax to indicate you can do calculations inside {} so you can apply that to your code.

Or you can calculate the result, put the result in the variable pcsPSHP and print that as you may need the value of pcsPSHP later for something else.

pcsPSHP = pcsBTS - pcsLWK 
print(f"{pcsPSHP}")

Have you done a Python tutorial? There are a bunch of free ones on Youtube and other sites. Some tutorials allow you to enter the code on the web page and run it immediately to help you practice. To find bugs and problems you will need to know how to think logically and understand how Python works, which is why I recommend you do a tutorial.

I’m not sure about this code:

            elif ScoreType == "FTS":                                        # Fielding Team Score (1 is added to this to generate 'target' as target is not a PCS variable
                pcsFTN = ScoreData
                pcsFTN = pcsFTN[:20]

Shouldn’t that be using pcsFTS instead of pcsFTN?

good spot, thanks.
I hadn’t noticed because FTS (Fielding Team Score) isn’t actually displayed on the board, it’s used to calculate ‘target’ which is FTS+1