Skip to content

Commit

Permalink
Adding a few features to the Bambu Connect installer.
Browse files Browse the repository at this point in the history
  • Loading branch information
QuinnDamerell committed May 25, 2024
1 parent e631ec4 commit 72f0436
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
// The module requires this json object to be passed.
// Normally the install.sh script runs, ensure everything is installed, creates a virtural env, and then runs this modlue giving it these args.
// But for debugging, we can skip that assuming it's already been ran.
"{\"OE_REPO_DIR\":\"/home/pi/octoeverywhere\",\"OE_ENV\":\"/home/pi/octoeverywhere-env\",\"USERNAME\":\"pi\",\"USER_HOME\":\"/home/pi\",\"CMD_LINE_ARGS\":\"-skipsudoactions -bambu\"}"
"{\"OE_REPO_DIR\":\"/home/pi/octoeverywhere\",\"OE_ENV\":\"/home/pi/octoeverywhere-env\",\"USERNAME\":\"pi\",\"USER_HOME\":\"/home/pi\",\"CMD_LINE_ARGS\":\"-skipsudoactions -bambu -debug\"}"
]
},
{
Expand Down
78 changes: 66 additions & 12 deletions linux_host/networksearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class NetworkSearch:
def ScanForInstances_Bambu(logger:logging.Logger, accessCode:str, printerSn:str, portStr:str = None) -> List[str]:
def callback(ip:str):
return NetworkSearch.ValidateConnection_Bambu(logger, ip, accessCode, printerSn, portStr, timeoutSec=5)
return NetworkSearch._ScanForInstances(logger, callback)
# We want to return if any one IP is found, since there can only be one printer that will match the printer 100% correct.
return NetworkSearch._ScanForInstances(logger, callback, returnAfterNumberFound=1)


# The final two steps can happen in different orders, so we need to wait for both the sub success and state object to be received.
Expand Down Expand Up @@ -190,7 +191,7 @@ def message(client, userdata:dict, mqttMsg:mqtt.MQTTMessage):
# testConFunction must be a function func(ip:str) -> NetworkValidationResult
# Returns a list of IPs that reported Success() == True
@staticmethod
def _ScanForInstances(logger:logging.Logger, testConFunction) -> List[str]:
def _ScanForInstances(logger:logging.Logger, testConFunction, returnAfterNumberFound = 0) -> List[str]:
foundIps = []
try:
localIp = NetworkSearch._TryToGetLocalIp()
Expand All @@ -207,25 +208,78 @@ def _ScanForInstances(logger:logging.Logger, testConFunction) -> List[str]:
return foundIps
ipPrefix = localIp[:lastDot+1]

# In the past, we did this wide with 255 threads.
# We got some feedback that the system was hanging on lower powered systems, but then I also found a bug where
# if an exception was thrown in the thread, it would hang the system.
# I fixed that but also lowered the concurrent thread count to 100, which seems more comfortable.
totalThreads = 100
outstandingIpsToCheck = []
counter = 0
while counter < 255:
# The first IP will be 1, the last 255
counter += 1
outstandingIpsToCheck.append(ipPrefix + str(counter))

# Start the threads
# We must use arrays so they get captured by ref in the threads.
doneThreads = [0]
totalThreads = 255
hasFoundRequestedNumberOfIps = [False]
threadLock = threading.Lock()
doneEvent = threading.Event()
while counter <= totalThreads:
fullIp = ipPrefix + str(counter)
def threadFunc(ip):
counter = 0
while counter < totalThreads:
def threadFunc(threadId):
try:
result = testConFunction(ip)
# Loop until we run out of IPs or the test is done by the bool flag.
while True:
# Get the next IP
ip = "none"
with threadLock:
# If there are no IPs left, this thread is done.
if len(outstandingIpsToCheck) == 0:
# This will invoke the finally block.
return
# If enough IPs have been found, we are done.
if hasFoundRequestedNumberOfIps[0] is True:
return
# Get the next IP.
ip = outstandingIpsToCheck.pop()

# Outside of lock, test the IP
result = testConFunction(ip)

# re-lock and set the result.
with threadLock:
# If successful, add the IP to the found list.
if result.Success():
# Enure we haven't already found the requested number of IPs,
# because then the result list might have already been returned
# and we don't want to mess with it.
if hasFoundRequestedNumberOfIps[0] is True:
return

# Add the IP to the list
foundIps.append(ip)

# Test if we have found all of the IPs we wanted to find.
if returnAfterNumberFound != 0 and len(foundIps) >= returnAfterNumberFound:
hasFoundRequestedNumberOfIps[0] = True
# We set this now, which allows the function to return the result list
# but the other threads will run until the current test ip is done.
# That's ok since we protect the result list from being added to.
doneEvent.set()
except Exception as e:
# Report the error.
logger.error(f"Server scan failed for {ip} "+str(e))
finally:
# Important - when we leave for any reason, mark this thread done.
with threadLock:
if result.Success():
foundIps.append(ip)
doneThreads[0] += 1
logger.debug(f"Thread {threadId} done. Done: {doneThreads[0]}; Total: {totalThreads}")
# If all of the threads are done, we are done.
if doneThreads[0] == totalThreads:
doneEvent.set()
except Exception as e:
logger.error(f"Server scan failed for {ip} "+str(e))
t = threading.Thread(target=threadFunc, args=[fullIp])
t = threading.Thread(target=threadFunc, args=(counter,))
t.start()
counter += 1
doneEvent.wait()
Expand Down
33 changes: 31 additions & 2 deletions py_installer/NetworkConnectors/BambuConnector.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def EnsureBambuConnection(self, context:Context):
Logger.Info(f"Keeping the existing Bambu Lab printer connection setup. {ip} - {printerSn}")
return

ipOrHostname, port, accessToken, printerSn = self._SetupNewBambuConnection()
ipOrHostname, port, accessToken, printerSn = self._SetupNewBambuConnection(context)
Logger.Info(f"You Bambu printer was found and authentication was successful! IP: {ipOrHostname}")

# Ensure the X1 camera is setup.
Expand All @@ -49,7 +49,7 @@ def EnsureBambuConnection(self, context:Context):

# Helps the user setup a bambu connection via auto scanning or manual setup.
# Returns (ip:str, port:str, accessToken:str, printerSn:str)
def _SetupNewBambuConnection(self):
def _SetupNewBambuConnection(self, context:Context):
while True:
Logger.Blank()
Logger.Blank()
Expand All @@ -62,6 +62,9 @@ def _SetupNewBambuConnection(self):
Logger.Info("Bambu Connect needs your printer's Access Code and Serial Number to connect to your printer.")
Logger.Info("If you have any trouble, we are happy to help! Contact us at support@octoeverywhere.com")

# Try to get an an existing access code or SN, so the user doesn't have to re-enter them if they are already there.
oldConfigAccessCode, oldConfigPrinterSn = ConfigHelper.TryToGetBambuData(context)

# Get the access code.
accessCode = None
while True:
Expand All @@ -75,6 +78,19 @@ def _SetupNewBambuConnection(self):
Logger.Blank()
Logger.Info("The access code is case sensitive - make sure to enter it exactly as shown on your printer.")
Logger.Blank()

# If there is already an access code, ask if the user wants to use it.
if oldConfigAccessCode is not None and len(oldConfigAccessCode) > 0:
Logger.Info(f"Your previously entered Access Code is: '{oldConfigAccessCode}'")
if Util.AskYesOrNoQuestion("Do you want to continue using this Access Code?"):
accessCode = oldConfigAccessCode
break
# Set it to None so we wont ask again.
oldConfigAccessCode = None
Logger.Blank()
Logger.Blank()

# Ask for the access code.
accessCode = input("Enter your printer's Access Code: ")

# Validate
Expand Down Expand Up @@ -112,6 +128,19 @@ def _SetupNewBambuConnection(self):
Logger.Warn("Follow this link for a step-by-step guide to find the Serial Number for your printer:")
Logger.Warn("https://octoeverywhere.com/s/bambu-sn")
Logger.Blank()

# If there is already an sn, ask if the user wants to use it.
if oldConfigPrinterSn is not None and len(oldConfigPrinterSn) > 0:
Logger.Info(f"Your previously entered Serial Number is: '{oldConfigPrinterSn}'")
if Util.AskYesOrNoQuestion("Do you want to continue using this Serial Number?"):
printerSn = oldConfigPrinterSn
break
# Set it to None so we wont ask again.
oldConfigPrinterSn = None
Logger.Blank()
Logger.Blank()

# Ask for the sn.
printerSn = input("Enter your printer's Serial Number: ")

# The SN should always be upper case letters.
Expand Down

0 comments on commit 72f0436

Please sign in to comment.