Here some Python code to fix the focus issue, and send commands to the cameras.I'm not the best programmer but it would be good place to start.
=================================================================================================================
import sys
import os
import brainboxes
import r_setup as s #you need a r_setup.py to initialize the public variables
import datetime
import time
import math
import requests
import subprocess
from decimal import Decimal
from requests.auth import HTTPDigestAuth
Here some Python code to fix the focus issue, and send commands to the cameras.I'm not the best programmer but it would be good place to start.
=================================================================================================================
import sys
import os
import brainboxes
import r_setup as s #you need a r_setup.py
import datetime
import time
import math
import requests
import subprocess
from decimal import Decimal
from subprocess import Popen, PIPE
from decimal import Decimal
from requests.auth import HTTPDigestAuth
def save_Log(errorLog):
    now = datetime.datetime.now()
    currdatetime = now.strftime("%Y-%m-%d %H:%M:%S")
    errorLogtmp = currdatetime + " - " + errorLog
    cr ="\n"
    text = open("r_error.log","a")
    print(errorLogtmp, file = text)  
    text.close()
def wait_key():
    ''' Wait for a key press on the console and return it. '''
    result = None
    if os.name == 'nt':
        import msvcrt
        result = msvcrt.getch()
    else:
        import termios
        fd = sys.stdin.fileno()
        oldterm = termios.tcgetattr(fd)
        newattr = termios.tcgetattr(fd)
        newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
        termios.tcsetattr(fd, termios.TCSANOW, newattr)
        try:
            result = sys.stdin.read(1)
        except IOError:
            pass
        finally:
            termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
    return result
def is_locked(filepath):
    """Checks if a file is locked by opening it in append mode.
    If no exception thrown, then the file is not locked.
    """
    locked = None
    file_object = None
    if os.path.exists(filepath):
        try:
            #print ("Trying to open %s." % filepath)
            buffer_size = 8
            # Opening file in append mode and read the first 8 characters.
            file_object = open(filepath, 'a', buffer_size)
            if file_object:
                #print ("%s is not locked." % filepath)
                locked = False
        except IOError:
            print ("File is locked (unable to open in append mode).")
                   
            locked = True
        finally:
            if file_object:
                file_object.close()
                print ("%s closed." % filepath)
    else:
        print ("%s not found." % filepath)
    return locked
def wait_for_files(filepath):
    """Checks if the files are ready.
     
    For a file to be ready it must exist and can be opened in append
    mode.
    """
    count = 0
    wait_time = 5
    #for filepath in filepaths:
    # If the file doesn't exist, wait wait_time seconds and try again
    # until it's found. Give up after 5 rounds
    while (not os.path.exists(filepath)) & (count < 4):
        print (filepath)
        print (filepath + " hasn't arrived. Waiting " + str(wait_time) + " seconds.")
        time.sleep(wait_time)
        count = count + 1
    # If the file exists but locked, wait wait_time seconds and check
    # again until it's no longer locked by another process.
    while is_locked(filepath):
        print (filepath + " is currently in use. Waiting " + str(wait_time) + " seconds.")
        time.sleep(wait_time)
########################
#                      #
#      Functions       #
#                      #
# Read from Comm Port  #
def _readline(self):
    eol = b'\r'
    leneol = len(eol)
    line = bytearray()
    if (serialData.inWaiting()>0): #if incoming bytes are waiting to be read from the serial input buffer
        while True:
            c = serialData.read(1)
            if c:
                line += c
                if line[-leneol:] == eol:
                    break
            else:
                break
    return bytes(line)
def insert_plate():
    sql = "INSERT INTO platedata "
    sql = sql + "(camera_label, epoch, events, vehicle_time, vehicle_jpg, vehicle_plate, vehicle_confidence, vehicle_region, vehicle_make_model, vehicle_year, vehicle_body_type, vehicle_make, vehicle_color)"
    sql = sql + " VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
    val = (s.cameraName, s.eventStart, s.events, s.videodatetime, s.picture, s.vehicle_plate, s.vehicle_confidence, s.vehicle_region, s.vehicle_make_model, s.vehicle_year, s.vehicle_body_type, s.vehicle_make, s.vehicle_color)
    print(sql)
    print(val)
    s.cursor.execute(sql, val)
    s.dbConn.commit() #commit the insert
    return
def update_plate():
    sql = "UPDATE platedata SET "
    sql = sql + "events = " + "'" + s.events + "'"
    sql = sql + ", vehicle_jpg = " + "'" + s.picture + "'"
    sql = sql + ", vehicle_plate_alias = " + "'" + s.last_vehicle_plate + "'"
    sql = sql + " WHERE vehicle_plate = " + "'" + s.vehicle_plate + "'"
    print(sql)
    s.cursor.execute(sql)
    s.dbConn.commit() #commit the insert
    return
def insert_speeddata():
    sql = "INSERT INTO speeddata "
    sql = sql + "(direction, MeasuredSpeed, minSpeed, maxSpeed, eventStart, currentUnixTime, Street, City, State, Zip, maxhourlyspeed, hourlyAverage, eventCounter, eventDuration, speedStart, speedEnd, speedersPerHour, videoRight, videoLeft, videodatetime, day, hour, quarter, minute)"
    sql = sql + " VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
    val = (LastDirection, eventSpeed, minSpeedData, maxSpeedData, eventStart, currentUnixTime, s.Street, s.City, s.State, s.Zip, maxHourlySpeed, hourlyAverage, eventCounter, eventDuration, speedStart, speedEnd, speedersPerHour, videoRight, videoLeft, videodatetime, DayofWeek, hour, quarter, minute)
    #print (sql)
    #print (val)
    s.cursor.execute(sql, val)
    s.dbConn.commit() #commit the insert
def insert_hourly():
    sql = "INSERT INTO HourlyReport "
    sql = sql + "(date, Hour, Events, Overspeeds, MaxHourly, AvgHourly, Percent, Day, eventStart)"
    sql = sql + " VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)"
    val = (date, LastTopOfHour, eventCounter, speedersPerHour, maxHourlySpeed, hourlyAverage, Percent, DayofWeek, maxEvent)
    s.cursor.execute(sql, val)
    s.dbConn.commit() #commit the insert
    return
def insert_quarterly():
    sql = "INSERT INTO QuarterlyReport "
    sql = sql + "(date, day, hour, minute, quarter, eventCounterQ, speedersPerQ, maxSpeedQ, AverageQ, PercentQ, eventStart)"
    sql = sql + " VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
    val = (date, DayofWeek, hour, minute, quarter, eventCounterQ, speedersPerQ, maxSpeedQ, AverageQ, PercentQ, maxEventQ)
    s.cursor.execute(sql, val)
    s.dbConn.commit() #commit the insert
    return
def write_speed_overlay():
        cr ="\n"
        overlay = "" + s.Street + " - " + s.City + ", " + s.State + cr
        overlay = overlay + "CST " + currdatetime + cr
        overlay = overlay + "Curr Epoch " + str(s.currentUnixTime) + cr
        overlay = overlay + "Start      " + str(s.eventStart) + cr
        overlay = overlay + "Event Dur          " + str(s.eventDuration) + cr         
        overlay = overlay + "Events/Hr  " + str(s.eventCounter) + cr
        overlay = overlay + "Direction  " + str(s.direction) + cr
        overlay = overlay + "Curr Speed " + str(s.MeasuredSpeed) + cr
        overlay = overlay + "Max Speed  " + str(s.maxSpeedData) + cr
        overlay = overlay + "Min Speed  " + str(s.minSpeedData) + cr
        overlay = overlay + "Hourly Max " + str(s.maxHourlySpeed) + cr
        overlay = overlay + "Hourly Avg " + str(s.hourlyAverage) + cr
        overlay = overlay + "OverSpd/Hr " + str(s.speedersPerHour)
        print (overlay)
        print (wait_for_files("speed.txt"))
        text= open("speed.txt","w")
        print(overlay, file = text)  
        text.close()
        return
     
def dstTest():
    dstTest = time.localtime().tm_isdst # localtime() returns a tuple
    # dstTest 0 = No DST  1 = DST Active  -1 = DST unknown
    return dstTest
     
def date_to_jd(year,month,day):
    # Convert a date to Julian Day.
    # Algorithm from 'Practical Astronomy with your Calculator or Spreadsheet',  
    # 4th ed., Duffet-Smith and Zwart, 2011.
    # This function extracted from 
    if month == 1 or month == 2:
        yearp = year - 1
        monthp = month + 12
    else:
        yearp = year
        monthp = month
    # this checks where we are in relation to October 15, 1582, the beginning
    # of the Gregorian calendar.
    if ((year < 1582) or
        (year == 1582 and month < 10) or
        (year == 1582 and month == 10 and day < 15)):
        # before start of Gregorian calendar
        B = 0
    else:
        # after start of Gregorian calendar
        A = math.trunc(yearp / 100.)
        B = 2 - A + math.trunc(A / 4.)
    if yearp < 0:
        C = math.trunc((365.25 * yearp) - 0.75)
    else:
        C = math.trunc(365.25 * yearp)
    D = math.trunc(30.6001 * (monthp + 1))
    jd = B + C + D + day + 1720994.5
    return jd     
# end of date_to_jd     
def sunrise():
    latitude_deg = s.lat
    longitude_deg = s.long
    timezone = s.timezone #we check for Daylight Savings Time and add 1 hour
    x = dstTest()
    if x == 1:
        timezone = timezone + 1
        print("DST is Active")
    pi=3.14159265359
    latitude_radians = math.radians(latitude_deg)
    longitude__radians = math.radians(longitude_deg)
    jd2000 = 2451545 #the julian date for Jan 1 2000 at noon
    currentDT = datetime.datetime.now()
    current_year = currentDT.year
    current_month = currentDT.month
    current_day = currentDT.day
    current_hour = currentDT.hour
    jd_now = date_to_jd(current_year,current_month,current_day)
    n = jd_now - jd2000 + 0.0008
    jstar = n - longitude_deg/360
    M_deg = (357.5291 + 0.98560028 * jstar)%360
    M = M_deg * pi/180
    C = 1.9148 * math.sin(M) + 0.0200 * math.sin(2*M) + 0.0003 * math.sin(3*M)
    lamda_deg = math.fmod(M_deg + C + 180 + 102.9372,360)
    lamda = lamda_deg * pi/180
    Jtransit = 2451545.5 + jstar + 0.0053 * math.sin(M) - 0.0069 * math.sin(2*lamda)
    earth_tilt_deg = 23.44
    earth_tilt_rad = math.radians(earth_tilt_deg)
    sin_delta = math.sin(lamda) * math.sin(earth_tilt_rad)
    angle_delta = math.asin(sin_delta)
    sun_disc_deg =  -0.83
    sun_disc_rad = math.radians(sun_disc_deg)
    cos_omega = (math.sin(sun_disc_rad) - math.sin(latitude_radians) * math.sin(angle_delta))/(math.cos(latitude_radians) * math.cos(angle_delta))
    omega_radians = math.acos(cos_omega)
    omega_degrees = math.degrees(omega_radians)
    #Output section
    print("------------------------------")
    print("Today's date is " + currentDT.strftime("%Y-%m-%d"))
    print("------------------------------")
    #("%Y-%m-%d %H:%M")
    print("Latitude =  " + str(latitude_deg))
    print("Longitude = " + str(longitude_deg))
    print("Timezone =  " + str(timezone))
    print("------------------------------")
    Jrise = Jtransit - omega_degrees/360
    numdays = Jrise - jd2000
    numdays =  numdays + 0.5 #offset because Julian dates start at noon
    numdays =  numdays + timezone/24 #offset for time zone
    sunrise = datetime.datetime(2000, 1, 1) + datetime.timedelta(numdays)
    print("Sunrise is at " + sunrise.strftime("%H:%M"))
    sunriseMidnight = (int(sunrise.strftime("%H"))*60) + int(sunrise.strftime("%M"))
    Jset = Jtransit + omega_degrees/360
    numdays = Jset - jd2000
    numdays =  numdays + 0.5 #offset because Julian dates start at noon
    numdays =  numdays + timezone/24 #offset for time zone
    sunset = datetime.datetime(2000, 1, 1) + datetime.timedelta(numdays)
    print("Sunset is at  " + sunset.strftime("%H:%M"))
    print("------------------------------")
    sunsetMidnight = (int(sunset.strftime("%H"))*60) + int(sunset.strftime("%M"))
    now = datetime.datetime.now()
    nowMinSinceMidnight = (int(now.strftime("%H"))*60) + int(now.strftime("%M"))
    s.sunRise = sunriseMidnight + 15
    s.sunSet = sunsetMidnight - 15 #15 minutes seems to work
    s.dayNight = ""
    if nowMinSinceMidnight < s.sunRise:
        set_all_cameras_night()
    if (nowMinSinceMidnight > s.sunRise) and (nowMinSinceMidnight < s.sunSet):
        set_all_cameras_day()
    if nowMinSinceMidnight > s.sunSet:
        set_all_cameras_night()
    return s.dayNight
def dayNightAdjust():
    now = datetime.datetime.now()
    nowMinSinceMidnight = (int(now.strftime("%H"))*60) + int(now.strftime("%M"))
    if (nowMinSinceMidnight < s.sunRise) and s.dayNight != "night":
        set_all_cameras_night()
    if (nowMinSinceMidnight > s.sunRise) and (nowMinSinceMidnight < s.sunSet) and s.dayNight != "day":
        set_all_cameras_day()
    if (nowMinSinceMidnight > s.sunSet) and s.dayNight != "night":
        set_all_cameras_night()
    return
def set_all_cameras_day():
        s.dayNight = "day"
        set_camera_day(s.ipCAM1)
        set_camera_day(s.ipCAM2)
        set_camera_day(s.ipCAM3)
        now = datetime.datetime.now()
        nowMinSinceMidnight = (int(now.strftime("%H"))*60) + int(now.strftime("%M"))
        save_Log("Set Day ** Sunrise ** All Cams " + str(nowMinSinceMidnight) + " - " + str(s.sunRise) + " - " + str(s.sunSet))
        set_manual_focus(0, s.ipCAM1) # day mode
        set_camera_color_mode(0, s.ipCAM1)
        time.sleep(.1)
        mode =1 # day mode
        set_focus_position(0, s.ipCAM1, s.focusCam1Day, s.zoomCam1Day)
        return
def set_all_cameras_night():
        s.dayNight = "night"
        set_camera_night(s.ipCAM1)
        set_camera_night(s.ipCAM2)
        set_camera_night(s.ipCAM3)
        now = datetime.datetime.now()
        nowMinSinceMidnight = (int(now.strftime("%H"))*60) + int(now.strftime("%M"))
        save_Log("Set Night ** Sunset ** All Cams " + str(nowMinSinceMidnight) + " - " + str(s.sunRise) + " - " + str(s.sunSet))
        set_manual_focus(1, s.ipCAM1) #night mode
        set_camera_bw_mode(1, s.ipCAM1)
        time.sleep(.1)
        set_focus_position(1, s.ipCAM1, s.focusCam1Night, s.zoomCam1Night)
        return
##########################################################################     
# request() gets from url, and returns the information in a Python list. #
# if an error is return it logs the command                              #
##########################################################################
def request(self):
    url = self
    r = requests.get(url, auth=HTTPDigestAuth(s.userCam, s.passwordCam))
    result = r.text.splitlines()
    if result[0] == 'Error':
        f.save_Log("**Error** - Request -> " + url)
    return result         
######################################################
# These Dahua commnds may not work for every camera. #
#  It depends on version and features                #
# send your ip address and it returns a list         #
######################################################
def set_camera_night(ipCAM):
        s.dayNight = "night"
        cmd = "/cgi-bin/configManager.cgi?action=setConfig&VideoInMode[0].Config[0]=1"
        cmdCAM = "http://" + ipCAM + cmd
        result = request(cmdCAM)
        if result[0] == 'Error':
            f.save_Log("**Error** - Set Camera Night -> " + ipCAM)
        return
     
def set_camera_day(ipCAM):
        s.dayNight = "day"
        cmd = "/cgi-bin/configManager.cgi?action=setConfig&VideoInMode[0].Config[0]=0"
        cmdCAM = "http://" + ipCAM + cmd
        result = request(cmdCAM)
        if result[0] == 'Error':
            f.save_Log("**Error** - Set Camera Day-> " + ipCAM)
        return
     
def set_camera_color_mode(mode, ipCAM): # 0 - day, 1 = night
        cmd = "/cgi-bin/configManager.cgi?action=setConfig&VideoInDayNight[0].Config[" + str(mode) + "].Mode=Color"
        cmdCAM = "http://" + ipCAM + cmd
        result = request(cmdCAM)
        if result[0] == 'Error':
            f.save_Log("**Error** - Set Camera Color -> " + ipCAM)
        return
     
def set_camera_bw_mode(mode, ipCAM): # 0 - day, 1 = night
        cmd = "/cgi-bin/configManager.cgi?action=setConfig&VideoInDayNight[0].Config[" + str(mode) + "].Mode=BlackWhite"
        cmdCAM = "http://" + ipCAM + cmd
        result = request(cmdCAM)
        if result[0] == 'Error':
            f.save_Log("**Error** - Set Cmaer BW -> " + ipCAM)
        return
     
def camera_reboot(ipCAM):
        cmd = "/cgi-bin/magicBox.cgi?action=reboot"
        cmdCAM = "http://" + ipCAM + cmd         
        result = request(cmdCAM)
        time.sleep(2)
        result = request(cmdCAM)
        if result[0] == 'Error':
            f.save_Log("**Error** - Camera Reboot -> " + ipCAM)
        return
     
def get_camera_exposure(ipCAM):
        cmdGetExposure = "/cgi-bin/configManager.cgi?action=getConfig&name=VideoInExposure"
        cmdCAM = "http://" + ipCAM + cmdGetExposure
        result = request(cmdCAM)
        if result[0] == 'Error':
            f.save_Log("**Error** - Get Camera Exposure -> " + ipCAM)
        return result
def set_manual_focus(mode, ipCAM): # mode = 0 day mode, 1 = day mode
        cmd = "/cgi-bin/configManager.cgi?action=setConfig&VideoInDayNight[0].Config[" + str(mode) + "].Mode=4"
        cmdCAM = "http://" + ipCAM + cmd
        result = request(cmdCAM)
        if result[0] == 'Error':
            f.save_Log("**Error** - Set Manual Focus -> " + ipCAM)
        return
   
def set_focus_position(mode, ipCAM, focus, zoom): # we approach position from same direction each time
        read_focus_settings()
        get_camera_focus_status(ipCAM)
        if s.focusReal != focus:
            cmd =  "/cgi-bin/devVideoInput.cgi?action=adjustFocus&focus=" + str(focus - Decimal(0.01)) +"&zoom=" + str(zoom)
            cmdCAM = "http://" + ipCAM + cmd
            result = request(cmdCAM)
            time.sleep(.3)
        cmd = "/cgi-bin/devVideoInput.cgi?action=adjustFocus&focus=" + str(focus) +"&zoom=" + str(zoom)
        cmdCAM = "http://" + ipCAM + cmd
        result = request(cmdCAM)  
        if result[0] == 'Error':
            f.save_Log("**Error** - Focus Set Position -> " + ipCAM)
        return
def get_camera_focus_status(ipCAM):
        cmdGetFocus = "/cgi-bin/devVideoInput.cgi?action=getFocusStatus"
        cmdCAM = "http://" + ipCAM + cmdGetFocus
        result = request(cmdCAM)
        temp = result[0].partition("=")[2]
        s.focusReal = int(Decimal(temp))
        temp = result[5].partition("=")[2]           
        s.zoomReal = int(Decimal(temp))
        if result[0] == 'Error':
            f.save_Log("**Error** - Focus Status -> " + ipCAM)
        return
def read_focus_settings():
    sql = "SELECT focusCam1Day, zoomCam1Day, focusCam1Night, zoomCam1Night FROM settings"
    s.cursor.execute(sql)
    result = s.cursor.fetchone()
    s.focusCam1Day = result[0]
    s.zoomCam1Day = result[1]
    s.focusCam1Night = result[2]
    s.zoomCam1Night = result[3]
    return