Added stick input and loops to macros

This commit is contained in:
Brikwerk 2020-06-08 21:23:23 -07:00
commit db4b550166
10 changed files with 384 additions and 61 deletions

67
demo.py
View file

@ -1,8 +1,7 @@
import time import time
from random import randint from random import randint
from nxbt import Nxbt import nxbt
from nxbt import ControllerTypes
MACRO = """ MACRO = """
B 0.1s B 0.1s
@ -13,25 +12,44 @@ B 0.1s
0.1s 0.1s
B 0.1s B 0.1s
1.5s 1.5s
DPAD_LEFT 0.1s
0.1s
DPAD_LEFT 0.1s
0.1s
DPAD_LEFT 0.1s
0.1s
DPAD_LEFT 0.1s
0.1s
DPAD_LEFT 0.1s
0.1s
DPAD_RIGHT 0.075s
0.075s
DPAD_RIGHT 0.075s
0.075s
DPAD_RIGHT 0.075s DPAD_RIGHT 0.075s
0.075s 0.075s
A 0.1s A 0.1s
1.5s 1.5s
DPAD_DOWN 1.0s
A 0.1s A 0.1s
0.25s
DPAD_DOWN 0.8s
A 0.1s
0.25s
L_STICK_PRESS 0.1s
1.0s
L_STICK@-100+000 0.75s
L_STICK@+000+100 0.75s
L_STICK@+100+000 0.75s
L_STICK@+000-100 0.75s
B 0.1s
0.25s
R_STICK_PRESS 0.1s
1.0s
R_STICK@-100+000 0.75s
R_STICK@+000+100 0.75s
R_STICK@+100+000 0.75s
R_STICK@+000-100 0.75s
B 0.1s
0.1s
B 0.1s
0.1s
B 0.1s
0.1s
B 0.1s
0.4s
DPAD_LEFT 0.1s
0.1s
A 0.1s
1.5s
A 0.1s
0.1s
""" """
@ -48,25 +66,26 @@ if __name__ == "__main__":
# Loop over all Bluetooth adapters and create # Loop over all Bluetooth adapters and create
# Switch Pro Controllers # Switch Pro Controllers
nxbt = Nxbt() nx = nxbt.Nxbt()
adapters = nxbt.get_available_adapters() adapters = nx.get_available_adapters()
# adapters = ["/org/bluez/hci0"]
controller_idxs = [] controller_idxs = []
for i in range(0, len(adapters)): for i in range(0, len(adapters)):
index = nxbt.create_controller( index = nx.create_controller(
ControllerTypes.PRO_CONTROLLER, nxbt.PRO_CONTROLLER,
adapters[i], adapters[i],
colour_body=random_colour(), colour_body=random_colour(),
colour_buttons=random_colour()) colour_buttons=random_colour())
controller_idxs.append(index) controller_idxs.append(index)
# Run a macro on the last controller # Run a macro on the last controller
nxbt.macro(controller_idxs[-1], MACRO, block=False) # and don't wait for the macro to complete
nx.macro(controller_idxs[-1], MACRO, block=False)
# Check the state # Check the state
while True: while True:
time.sleep(1) time.sleep(1)
for key in nxbt.state.keys(): for key in nx.state.keys():
state = nxbt.state[key] state = nx.state[key]
if not state["errors"]: if not state["errors"]:
print(state) print(state)
else: else:

View file

@ -1,8 +1,10 @@
from .controller import ControllerServer from .controller import ControllerServer
from .controller import ControllerTypes
from .controller import ControllerProtocol from .controller import ControllerProtocol
from .controller import SwitchReportParser from .controller import SwitchReportParser
from .controller import SwitchResponses from .controller import SwitchResponses
from .controller import Controller from .controller import Controller
from .bluez import * from .bluez import *
from .nxbt import Nxbt from .nxbt import Nxbt
from .nxbt import JOYCON_L
from .nxbt import JOYCON_R
from .nxbt import PRO_CONTROLLER

View file

@ -1,5 +1,124 @@
import argparse
import time
from random import randint
from .web import start_web_app from .web import start_web_app
from .nxbt import Nxbt, PRO_CONTROLLER
parser = argparse.ArgumentParser()
parser.add_argument('command', default=False, choices=['start', 'demo'],
help="Specifies the Nxbt command to run")
args = parser.parse_args()
MACRO = """
LOOP 100
B 0.1s
0.1s
B 0.1s
0.1s
B 0.1s
0.1s
B 0.1s
1.5s
DPAD_RIGHT 0.075s
0.075s
A 0.1s
1.5s
DPAD_DOWN 1.0s
A 0.1s
0.25s
DPAD_DOWN 0.8s
A 0.1s
0.25s
L_STICK_PRESS 0.1s
1.0s
L_STICK@-100+000 0.75s
L_STICK@+000+100 0.75s
L_STICK@+100+000 0.75s
L_STICK@+000-100 0.75s
B 0.1s
0.25s
R_STICK_PRESS 0.1s
1.0s
R_STICK@-100+000 0.75s
R_STICK@+000+100 0.75s
R_STICK@+100+000 0.75s
R_STICK@+000-100 0.75s
B 0.1s
0.1s
B 0.1s
0.1s
B 0.1s
0.1s
B 0.1s
0.4s
DPAD_LEFT 0.1s
0.1s
A 0.1s
1.5s
A 0.1s
20.0s
"""
MACRO = """
B 0.1s
3.0s
A 0.1s
3.0s
20.0s
B 0.1s
LOOP 100
B 0.1s
0.1s
"""
def random_colour():
return [
randint(0, 255),
randint(0, 255),
randint(0, 255),
]
def demo():
"""Loops over all available Bluetooth adapters
and creates controllers on each. The last available adapter
is used to run a macro.
"""
nx = Nxbt()
adapters = nx.get_available_adapters()
controller_idxs = []
for i in range(0, len(adapters)):
index = nx.create_controller(
PRO_CONTROLLER,
adapters[i],
colour_body=random_colour(),
colour_buttons=random_colour())
controller_idxs.append(index)
# Run a macro on the last controller
# and don't wait for the macro to complete
nx.macro(controller_idxs[-1], MACRO, block=False)
# Check the state
while True:
time.sleep(1)
for key in nx.state.keys():
state = nx.state[key]
if not state["errors"]:
print(state)
else:
print(state["errors"])
def main(): def main():
start_web_app()
if args.command == 'start':
start_web_app()
elif args.command == 'demo':
demo()

View file

@ -3,12 +3,34 @@ from time import perf_counter
class InputParser(): class InputParser():
# Left Stick calibration values
LEFT_STICK_CALIBRATION = {
"center_x": 2159,
"center_y": 1916,
# Zeroed Min/Max X and Y
"min_x": -1466,
"max_x": 1517,
"min_y": -1583,
"max_y": 1465,
}
# Right Stick calibration values
RIGHT_STICK_CALIBRATION = {
"center_x": 2070,
"center_y": 2013,
# Zeroed Min/Max X and Y
"min_x": -1522,
"max_x": 1414,
"min_y": -1531,
"max_y": 1510,
}
def __init__(self, protocol): def __init__(self, protocol):
self.protocol = protocol self.protocol = protocol
# Buffers a list of unparsed macros # Buffers a list of unparsed macros
self.macro_buffer = [] self.macro_buffer = []
# Keeps track of the entire current # Keeps track of the entire current
# list of macro commands. # list of macro commands.
self.current_macro = None self.current_macro = None
@ -16,8 +38,10 @@ class InputParser():
# Keeps track of the macro commands being # Keeps track of the macro commands being
# input over a period of time. # input over a period of time.
self.current_macro_commands = None self.current_macro_commands = None
# The time length of the current macro # The time length of the current macro
self.macro_timer_length = 0 self.macro_timer_length = 0
# The start time for the current macro commands # The start time for the current macro commands
self.macro_timer_start = 0 self.macro_timer_start = 0
@ -47,8 +71,7 @@ class InputParser():
if not self.current_macro and self.macro_buffer: if not self.current_macro and self.macro_buffer:
# Preprocess command lines of current macro # Preprocess command lines of current macro
macro = self.macro_buffer.pop(0) macro = self.macro_buffer.pop(0)
self.current_macro = macro[0].strip("\n") self.current_macro = self.parse_macro(macro[0])
self.current_macro = self.current_macro.split("\n")
self.current_macro_id = macro[1] self.current_macro_id = macro[1]
# Check if we can load the next set of commands # Check if we can load the next set of commands
@ -62,6 +85,7 @@ class InputParser():
self.macro_timer_length = float(timer_length) self.macro_timer_length = float(timer_length)
self.macro_timer_start = perf_counter() self.macro_timer_start = perf_counter()
print(self.current_macro_commands)
self.parse_macro_input(self.current_macro_commands) self.parse_macro_input(self.current_macro_commands)
# Check if we're done inputting the current command # Check if we're done inputting the current command
@ -78,6 +102,57 @@ class InputParser():
return controller_input return controller_input
def parse_macro(self, macro):
parsed = macro.split("\n")
parsed = list(filter(lambda s: not s.strip() == "", parsed))
parsed = self.parse_loops(parsed)
return parsed
def parse_loops(self, macro):
parsed = []
i = 0
while i < len(macro):
line = macro[i]
if line.startswith("LOOP"):
loop_count = int(line.split(" ")[1])
loop_buffer = []
# Detect delimiter and record
if macro[i+1].startswith("\t"):
loop_delimiter = "\t"
elif macro[i+1].startswith(" "):
loop_delimiter = " "
else:
loop_delimiter = " "
# Gather looping commands
for j in range(i+1, len(macro)):
loop_line = macro[j]
if loop_line.startswith(loop_delimiter):
# Replace the first instance of the delimiter
loop_line = loop_line.replace(loop_delimiter, "", 1)
loop_buffer.append(loop_line)
# Set the new position if we either encounter the end
# of the loop or we reach the end of the macro
else:
i = j - 1
break
if j+1 >= len(macro):
i = j
# Recursively gather other loops if present
if any(s.startswith("LOOP") for s in loop_buffer):
loop_buffer = self.parse_loops(loop_buffer)
# Multiply out the loop and concatenate
parsed = parsed + (loop_buffer * loop_count)
else:
parsed.append(line)
i += 1
return parsed
def parse_macro_input(self, macro_input): def parse_macro_input(self, macro_input):
# Checking if this is a wait macro command # Checking if this is a wait macro command
@ -89,6 +164,9 @@ class InputParser():
upper = ['0'] * 8 upper = ['0'] * 8
shared = ['0'] * 8 shared = ['0'] * 8
lower = ['0'] * 8 lower = ['0'] * 8
# Analog stick byte placeholders
stick_left = None
stick_right = None
for i in range(0, len(macro_input)-1): for i in range(0, len(macro_input)-1):
button = macro_input[i] button = macro_input[i]
# Upper Byte # Upper Byte
@ -114,9 +192,9 @@ class InputParser():
shared[7] = '1' shared[7] = '1'
elif button == "+": elif button == "+":
shared[6] = '1' shared[6] = '1'
elif button == "R_ANALOG_DOWN": elif button == "R_STICK_PRESS":
shared[5] = '1' shared[5] = '1'
elif button == "L_ANALOG_DOWN": elif button == "L_STICK_PRESS":
shared[4] = '1' shared[4] = '1'
elif button == "HOME": elif button == "HOME":
shared[3] = '1' shared[3] = '1'
@ -141,9 +219,84 @@ class InputParser():
elif button == "ZL": elif button == "ZL":
lower[0] = '1' lower[0] = '1'
# Analog Stick Positions
elif button.startswith("L_STICK@"):
stick_left = self.parse_macro_stick_position(button)
elif button.startswith("R_STICK@"):
stick_right = self.parse_macro_stick_position(button)
# Converting binary strings to ints # Converting binary strings to ints
upper_byte = int("".join(upper), 2) upper_byte = int("".join(upper), 2)
shared_byte = int("".join(shared), 2) shared_byte = int("".join(shared), 2)
lower_byte = int("".join(lower), 2) lower_byte = int("".join(lower), 2)
self.protocol.set_button_inputs(upper_byte, shared_byte, lower_byte) self.protocol.set_button_inputs(upper_byte, shared_byte, lower_byte)
if stick_left:
self.protocol.set_left_stick_inputs(stick_left)
if stick_right:
self.protocol.set_right_stick_inputs(stick_right)
def parse_macro_stick_position(self, stick_pos):
stick_type = stick_pos.split("@")[0]
positions = stick_pos.split("@")[1]
if len(positions) < 8:
return None
# Converting macro to proper ratios
sign_x = positions[0]
ratio_x = int(positions[1:4]) / 100
if sign_x == "-":
ratio_x = ratio_x * -1
sign_y = positions[4]
ratio_y = int(positions[5:8]) / 100
if sign_y == "-":
ratio_y = ratio_y * -1
calibrated_position = self.stick_ratio_to_calibrated_position(
ratio_x, ratio_y, stick_type)
return calibrated_position
def stick_ratio_to_calibrated_position(self, ratio_x, ratio_y, stick_type):
# Using the appropriate calibration values for the stick type
if stick_type == "L_STICK":
cal = self.LEFT_STICK_CALIBRATION
else:
cal = self.RIGHT_STICK_CALIBRATION
# Converting ratios to uint16 values
if ratio_x < 0:
data_x_converted = (
abs(ratio_x) * cal["min_x"] + cal["center_x"])
else:
data_x_converted = (
abs(ratio_x) * cal["max_x"] + cal["center_x"])
data_x_converted = int(round(data_x_converted))
if ratio_y < 0:
data_y_converted = (
abs(ratio_y) * cal["min_y"] + cal["center_y"])
else:
data_y_converted = (
abs(ratio_y) * cal["max_y"] + cal["center_y"])
data_y_converted = int(round(data_y_converted))
# Converting the two X/Y uint16 values to 3 uint8 Little Endian values
# using bitshifting techniques
converted_values = [
# Get the last two hex digits
data_x_converted & 0xFF,
# Combine the last digit of the Y uint16 and the first digit
# of the X uint16
((data_y_converted & 0xF) << 4) + (data_x_converted >> 8),
# Get the first two digits of the Y uint16
data_y_converted >> 4]
return converted_values
def reassign_protocol(self, protocol):
self.protocol = protocol

View file

@ -3,7 +3,7 @@ import random
from time import perf_counter from time import perf_counter
from .controller import ControllerTypes from .controller import ControllerTypes
from .utils import replace_subarray from .utils import replace_subarray, format_msg_controller
class SwitchResponses(Enum): class SwitchResponses(Enum):
@ -97,19 +97,19 @@ class ControllerProtocol():
# Disable left stick if we have a right Joy-Con # Disable left stick if we have a right Joy-Con
if self.controller_type == ControllerTypes.JOYCON_R: if self.controller_type == ControllerTypes.JOYCON_R:
self.left_stick_status = [0x00] * 3 self.left_stick_centre = [0x00] * 3
else: else:
# Center values which are also reported under # Center values which are also reported under
# SPI Stick calibration reads # SPI Stick calibration reads
self.left_stick_status = [0x6F, 0xC8, 0x77] self.left_stick_centre = [0x6F, 0xC8, 0x77]
# Disable right stick if we have a left Joy-Con # Disable right stick if we have a left Joy-Con
if self.controller_type == ControllerTypes.JOYCON_L: if self.controller_type == ControllerTypes.JOYCON_L:
self.right_stick_status = [0x00] * 3 self.right_stick_centre = [0x00] * 3
else: else:
# Center values which are also reported under # Center values which are also reported under
# SPI Stick calibration reads # SPI Stick calibration reads
self.right_stick_status = [0x16, 0xD8, 0x7D] self.right_stick_centre = [0x16, 0xD8, 0x7D]
self.vibrator_report = random.choice(self.VIBRATOR_BYTES) self.vibrator_report = random.choice(self.VIBRATOR_BYTES)
@ -130,6 +130,7 @@ class ControllerProtocol():
def get_report(self): def get_report(self):
report = bytes(self.report) report = bytes(self.report)
print(format_msg_controller(report))
# Clear report # Clear report
self.set_empty_report() self.set_empty_report()
return report return report
@ -266,22 +267,35 @@ class ControllerProtocol():
self.report[5] = self.button_status[1] self.report[5] = self.button_status[1]
self.report[6] = self.button_status[2] self.report[6] = self.button_status[2]
self.report[7] = self.left_stick_status[0] self.report[7] = self.left_stick_centre[0]
self.report[8] = self.left_stick_status[1] self.report[8] = self.left_stick_centre[1]
self.report[9] = self.left_stick_status[2] self.report[9] = self.left_stick_centre[2]
self.report[10] = self.right_stick_status[0] self.report[10] = self.right_stick_centre[0]
self.report[11] = self.right_stick_status[1] self.report[11] = self.right_stick_centre[1]
self.report[12] = self.right_stick_status[2] self.report[12] = self.right_stick_centre[2]
self.report[13] = self.vibrator_report self.report[13] = self.vibrator_report
def set_button_inputs(self, upper, shared, lower): def set_button_inputs(self, upper, shared, lower):
print(upper, shared, lower)
self.report[4] = upper self.report[4] = upper
self.report[5] = shared self.report[5] = shared
self.report[6] = lower self.report[6] = lower
def set_left_stick_inputs(self, left):
self.report[7] = left[0]
self.report[8] = left[1]
self.report[9] = left[2]
def set_right_stick_inputs(self, right):
self.report[10] = right[0]
self.report[11] = right[1]
self.report[12] = right[2]
def set_device_info(self): def set_device_info(self):
# ACK Reply # ACK Reply

View file

@ -104,7 +104,6 @@ class ControllerServer():
if self.task_queue: if self.task_queue:
try: try:
msg = self.task_queue.get_nowait() msg = self.task_queue.get_nowait()
print(msg)
if msg: if msg:
self.input.buffer_macro( self.input.buffer_macro(
msg["macro"], msg["macro_id"]) msg["macro"], msg["macro_id"])
@ -115,8 +114,8 @@ class ControllerServer():
self.input.set_protocol_input(state=self.state) self.input.set_protocol_input(state=self.state)
msg = self.protocol.get_report() msg = self.protocol.get_report()
if reply: # if reply:
print(format_msg_controller(msg)) # print(format_msg_controller(msg))
try: try:
itr.sendall(msg) itr.sendall(msg)
@ -168,6 +167,7 @@ class ControllerServer():
self.bt.address, self.bt.address,
colour_body=self.colour_body, colour_body=self.colour_body,
colour_buttons=self.colour_buttons) colour_buttons=self.colour_buttons)
self.input.reassign_protocol(self.protocol)
if self.lock: if self.lock:
self.lock.acquire() self.lock.acquire()

View file

@ -8,10 +8,16 @@ import os
import dbus import dbus
from .controller import ControllerServer from .controller import ControllerServer
from .controller import ControllerTypes
from .bluez import find_objects, toggle_input_plugin from .bluez import find_objects, toggle_input_plugin
from .bluez import SERVICE_NAME, ADAPTER_INTERFACE from .bluez import SERVICE_NAME, ADAPTER_INTERFACE
JOYCON_L = ControllerTypes.JOYCON_L
JOYCON_R = ControllerTypes.JOYCON_R
PRO_CONTROLLER = ControllerTypes.PRO_CONTROLLER
class NxbtCommands(Enum): class NxbtCommands(Enum):
CREATE_CONTROLLER = 0 CREATE_CONTROLLER = 0
@ -147,7 +153,7 @@ class Nxbt():
# Block until the controller is ready # Block until the controller is ready
# This needs to be done to prevent race conditions # This needs to be done to prevent race conditions
# on DBus resources. # on Bluetooth resources.
if type(controller_index) == int: if type(controller_index) == int:
while True: while True:
if controller_index in self.manager_state.keys(): if controller_index in self.manager_state.keys():
@ -157,7 +163,6 @@ class Nxbt():
break break
finally: finally:
self.__controller_lock.release() self.__controller_lock.release()
pass
return controller_index return controller_index

View file

@ -15,7 +15,7 @@ from time import perf_counter
from nxbt import toggle_input_plugin from nxbt import toggle_input_plugin
from nxbt import BlueZ from nxbt import BlueZ
from nxbt import Controller from nxbt import Controller
from nxbt import ControllerTypes from nxbt import JOYCON_L, JOYCON_R, PRO_CONTROLLER
JCL_REPLY02 = b'\xA2\x21\x05\x8E\x84\x00\x12\x01\x18\x80\x01\x18\x80\x80\x82\x02\x03\x48\x01\x02\xDC\xA6\x32\x16\x4A\x7C\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' JCL_REPLY02 = b'\xA2\x21\x05\x8E\x84\x00\x12\x01\x18\x80\x01\x18\x80\x80\x82\x02\x03\x48\x01\x02\xDC\xA6\x32\x16\x4A\x7C\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
@ -95,10 +95,10 @@ if __name__ == "__main__":
# Switch Controller Bluetooth MAC Address goes here # Switch Controller Bluetooth MAC Address goes here
jc_MAC = "7C:BB:8A:FA:41:3D" jc_MAC = "7C:BB:8A:FA:41:3D"
# Specify the type of controller here # Specify the type of controller here
controller_type = ControllerTypes.PRO_CONTROLLER controller_type = PRO_CONTROLLER
if controller_type == ControllerTypes.JOYCON_L: if controller_type == JOYCON_L:
REPLY = JCL_REPLY02 REPLY = JCL_REPLY02
elif controller_type == ControllerTypes.JOYCON_R: elif controller_type == JOYCON_R:
REPLY = JCR_REPLY02 REPLY = JCR_REPLY02
else: else:
REPLY = PRO_REPLY02 REPLY = PRO_REPLY02

View file

@ -24,10 +24,10 @@ data_right[5] = (stick_cal_right[8] << 4) | (stick_cal_right[7] >> 4)
# Left Stick Decode # Left Stick Decode
left_center_x = data_left[2] left_center_x = data_left[2]
left_center_y = data_left[3] left_center_y = data_left[3]
left_x_min = left_center_x - data_left[0] left_x_min = (left_center_x - data_left[0]) - left_center_x
left_x_max = left_center_x + data_left[4] left_x_max = (left_center_x + data_left[4]) - left_center_x
left_y_min = left_center_y - data_left[1] left_y_min = (left_center_y - data_left[1]) - left_center_y
left_y_max = left_center_y + data_left[5] left_y_max = (left_center_y + data_left[5]) - left_center_y
print("Left Stick Values:") print("Left Stick Values:")
print("~~~~~~~~~~~~~~~~~~") print("~~~~~~~~~~~~~~~~~~")
@ -38,10 +38,10 @@ print("Left Y Min/Max: ", left_y_min, "", left_y_max)
# Right Stick Decode # Right Stick Decode
right_center_x = data_right[0] right_center_x = data_right[0]
right_center_y = data_right[1] right_center_y = data_right[1]
right_x_min = right_center_x - data_right[2] right_x_min = (right_center_x - data_right[2]) - right_center_x
right_x_max = right_center_x + data_right[4] right_x_max = (right_center_x + data_right[4]) - right_center_x
right_y_min = right_center_y - data_right[3] right_y_min = (right_center_y - data_right[3]) - right_center_y
right_y_max = right_center_y + data_right[5] right_y_max = (right_center_y + data_right[5]) - right_center_y
print("\nRight Stick Values:") print("\nRight Stick Values:")
print("~~~~~~~~~~~~~~~~~~~") print("~~~~~~~~~~~~~~~~~~~")
@ -63,9 +63,20 @@ print("Relative X/Y Values", ratio_x, ratio_y)
print("\nExample Left Stick Ratio to Data Conversion:") print("\nExample Left Stick Ratio to Data Conversion:")
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
data_x_converted = (abs(ratio_x) * (left_x_min - left_center_x) + left_center_x) if ratio_x < 0:
data_x_converted = (
abs(ratio_x) * (left_x_min - left_center_x) + left_center_x)
else:
data_x_converted = (
abs(ratio_x) * (left_x_max - left_center_x) + left_center_x)
data_x_converted = int(round(data_x_converted)) data_x_converted = int(round(data_x_converted))
data_y_converted = (abs(ratio_y) * (left_y_min - left_center_y) + left_center_y)
if ratio_y < 0:
data_y_converted = (
abs(ratio_y) * (left_y_min - left_center_y) + left_center_y)
else:
data_y_converted = (
abs(ratio_y) * (left_y_max - left_center_y) + left_center_y)
data_y_converted = int(round(data_y_converted)) data_y_converted = int(round(data_y_converted))
print("X/Y Converted Values:", data_x_converted, data_y_converted) print("X/Y Converted Values:", data_x_converted, data_y_converted)

View file

@ -43,5 +43,5 @@ filterwarnings =
error error
[flake8] [flake8]
max-line-length = 80 max-line-length = 100
exclude = .git, .eggs, __pycache__, tests/, docs/, build/, dist/ exclude = .git, .eggs, __pycache__, tests/, docs/, build/, dist/