moons-motor 0.0.11__py3-none-any.whl → 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
moons_motor/motor.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import serial
2
+ import serial.rs485
2
3
  from serial.tools import list_ports
3
4
  import re
4
5
  import threading
@@ -8,12 +9,51 @@ from rich.panel import Panel
8
9
  import queue
9
10
  from moons_motor.subject import Subject
10
11
  import time
12
+ import threading
13
+
14
+ from dataclasses import dataclass
11
15
 
12
16
 
13
17
  class StepperModules:
14
18
  STM17S_3RN = "STM17S-3RN"
15
19
 
16
20
 
21
+ @dataclass(frozen=True)
22
+ class StepperCommand:
23
+ JOG: str = "CJ" # Start jogging
24
+ JOG_SPEED: str = "JS" # Jogging speed (Need to set before start jogging)
25
+ CHANGE_JOG_SPEED: str = "CS" # Change jogging speed while jogging
26
+ STOP_JOG: str = "SJ" # Stop jogging with deceleration
27
+ STOP: str = "ST" # Stop immediately (No deceleration)
28
+ STOP_DECEL: str = "STD" # Stop with deceleration
29
+ STOP_KILL: str = (
30
+ "SK" # Stop with deceleration(Control by AM) and kill all unexecuted commands
31
+ )
32
+ STOP_KILL_DECEL: str = (
33
+ "SKD" # Stop and kill all unexecuted commands with deceleration(Control by DE)
34
+ )
35
+ ENABLE: str = "ME" # Enable motor
36
+ DISABLE: str = "MD" # Disable motor
37
+ MOVE_ABSOLUTE: str = "FP" # Move to absolute position
38
+ MOVE_FIXED_DISTANCE: str = "FL" # Move to fixed distance
39
+ POSITION: str = "IP" # Motor absolute position(Calculated trajectory position)
40
+ TEMPERATURE: str = "IT" # Motor temperature
41
+ VOLTAGE: str = "IU" # Motor voltage
42
+
43
+ ENCODER_POSITION: str = "EP" # Encoder position
44
+ SET_POSITION: str = "SP" # Set encoder position
45
+
46
+ HOME: str = "SH" # Home position
47
+ VELOCITY: str = "VE" # Set velocity
48
+
49
+ ALARM_RESET: str = "AR" # Reset alarm
50
+
51
+ SET_RETURN_FORMAT_DECIMAL: str = "IFD" # Set return format to decimal
52
+ SET_RETURN_FORMAT_HEXADECIMAL: str = "IFH" # Set return format to hexadecimal
53
+
54
+ SET_TRANSMIT_DELAY: str = "TD" # Set transmit delay
55
+
56
+
17
57
  class MoonsStepper(Subject):
18
58
  motorAdress = [
19
59
  "0",
@@ -61,25 +101,20 @@ class MoonsStepper(Subject):
61
101
  ):
62
102
  super().__init__()
63
103
  self.universe = universe
64
- self.model = model
104
+ self.model = model # Motor model
65
105
  self.only_simulate = only_simlate
66
- self.device = ""
106
+ self.device = "" # COM port description
67
107
  self.VID = VID
68
108
  self.PID = PID
69
- self.SERIAL_NUM = SERIAL_NUM
109
+ self.SERIAL_NUM = SERIAL_NUM # ID for determent the deivice had same VID and PID, can be config using chips manufacturer tool
70
110
  self.ser = None
71
- self.listeningBuffer = ""
72
- self.listeningBufferPre = ""
73
- self.transmitDelay = 0.010
74
- self.lock = False
75
111
  self.Opened = False
76
- self.new_data_event = threading.Event()
77
- self.new_value_event = threading.Event()
78
- self.on_send_event = threading.Event()
79
112
  self.recvQueue = queue.Queue()
80
113
  self.sendQueue = queue.Queue()
81
- self.command_cache = queue.Queue()
82
- self.usedSendQueue = queue.Queue()
114
+ self.pending_callbacks = queue.Queue()
115
+ self.update_thread = None
116
+ self.is_updating = False
117
+ self.readBuffer = ""
83
118
 
84
119
  self.console = Console()
85
120
 
@@ -117,7 +152,29 @@ class MoonsStepper(Subject):
117
152
  print(Panel(port_info, title="All COMPorts"))
118
153
  return simple_ports
119
154
 
155
+ @staticmethod
156
+ def process_response(response):
157
+ equal_sign_index = response.index("=")
158
+ address = response[0]
159
+ command = response[1:equal_sign_index]
160
+ value = response[equal_sign_index + 1 :]
161
+
162
+ if command == "IT" or command == "IU":
163
+ # Handle temperature response
164
+ value = int(value) / 10.0
165
+ return {
166
+ "address": address,
167
+ "command": command,
168
+ "value": value,
169
+ }
170
+
171
+ def __start_update_thread(self):
172
+ self.update_thread = threading.Thread(target=self.update, daemon=True)
173
+ self.is_updating = True
174
+ self.update_thread.start()
175
+
120
176
  def connect(self, COM=None, baudrate=9600, callback=None):
177
+ # Simulate mode
121
178
  if self.only_simulate:
122
179
  self.Opened = True
123
180
  self.device = f"Simulate-{self.universe}"
@@ -128,57 +185,80 @@ class MoonsStepper(Subject):
128
185
 
129
186
  def attempt_connect(COM, baudrate):
130
187
  try:
131
- self.ser = serial.Serial(COM, baudrate)
188
+ # self.ser = serial.Serial(
189
+ # port=COM,
190
+ # baudrate=baudrate,
191
+ # bytesize=serial.EIGHTBITS,
192
+ # parity=serial.PARITY_NONE,
193
+ # stopbits=serial.STOPBITS_ONE,
194
+ # timeout=0.5,
195
+ # )
196
+ self.ser = serial.rs485.RS485(port=COM, baudrate=baudrate)
197
+ self.ser.rs485_mode = serial.rs485.RS485Settings(
198
+ rts_level_for_tx=True,
199
+ rts_level_for_rx=False,
200
+ loopback=False,
201
+ delay_before_tx=0.02,
202
+ delay_before_rx=0.02,
203
+ )
132
204
  if self.ser is None:
133
- # print("> Device not found")
134
205
  self.Opened = False
135
206
  if self.ser.is_open:
136
- # print(f"Device: {self.device} | COM: {COM} connected")
137
207
  self.Opened = True
138
- except:
139
- print("> Device error")
208
+ print(f"[bold green]Device connected[/bold green]: {self.device}")
209
+
210
+ except Exception as e:
211
+ print(f"[bold red]Device error:[/bold red] {e} ")
140
212
  self.Opened = False
141
213
 
214
+ ports = list(list_ports.comports())
142
215
  if COM is not None and not self.only_simulate:
143
216
  attempt_connect(COM, baudrate)
144
217
  if callback:
145
218
  callback(self.device, self.Opened)
146
- return
147
- ports = list(list_ports.comports())
148
- for p in ports:
149
- m = re.match(
150
- r"USB\s*VID:PID=(\w+):(\w+)\s*SER=([A-Za-z0-9]*)", p.usb_info()
151
- )
152
- print(m, p.usb_info())
153
- if (
154
- m
155
- and m.group(1) == self.VID
156
- and m.group(2) == self.PID
157
- # and m.group(3) == self.SERIAL_NUM
158
- ):
159
- print("find vid pid match")
160
- if m.group(3) == self.SERIAL_NUM or self.SERIAL_NUM == "":
161
- print(
162
- f"Device: {p.description} | VID: {m.group(1)} | PID: {m.group(2)} | SER: {m.group(3)} connected"
163
- )
164
-
165
- self.device = p.description
166
-
167
- attempt_connect(p.device, baudrate)
168
- if callback:
169
- callback(self.device, self.Opened)
219
+ else:
220
+ for p in ports:
221
+ m = re.match(
222
+ r"USB\s*VID:PID=(\w+):(\w+)\s*SER=([A-Za-z0-9]*)", p.usb_info()
223
+ )
224
+ print(p.usb_info())
225
+ if (
226
+ m
227
+ and m.group(1) == self.VID
228
+ and m.group(2) == self.PID
229
+ # and m.group(3) == self.SERIAL_NUM
230
+ ):
231
+ if m.group(3) == self.SERIAL_NUM or self.SERIAL_NUM == "":
232
+ print(
233
+ f"[bold yellow]Device founded:[/bold yellow] {p.description} | VID: {m.group(1)} | PID: {m.group(2)} | SER: {m.group(3)}"
234
+ )
235
+
236
+ self.device = p.description
237
+
238
+ attempt_connect(p.device, baudrate)
239
+
170
240
  break
171
- break
172
241
 
173
- if self.only_simulate:
174
- self.device = "Simulate"
175
- self.Opened = True
242
+ if self.only_simulate:
243
+ self.device = "Simulate"
244
+ self.Opened = True
245
+ time.sleep(0.5)
246
+ self.__start_update_thread()
247
+ if callback:
248
+ callback(self.device, self.Opened)
249
+
176
250
  if not self.Opened:
177
- print("> Device not found")
251
+ print(f"[bold red]Device not found[/bold red]")
178
252
  if callback:
179
253
  callback(self.device, self.Opened)
180
254
 
181
255
  def disconnect(self):
256
+ self.send_command(command=StepperCommand.STOP_KILL)
257
+ time.sleep(0.5)
258
+ self.sendQueue.queue.clear()
259
+ self.recvQueue.queue.clear()
260
+ self.is_updating = False
261
+ self.update_thread = None
182
262
  if self.only_simulate:
183
263
  self.listen = False
184
264
  self.is_sending = False
@@ -191,19 +271,13 @@ class MoonsStepper(Subject):
191
271
  self.Opened = False
192
272
  self.ser.flush()
193
273
  self.ser.close()
194
- print(f"{self.device} Disconnected")
274
+ print(f"[bold red]Device disconnected[/bold red]: {self.device}")
195
275
 
196
276
  def send(self, command, eol=b"\r"):
197
277
  if (self.ser != None and self.ser.is_open) or self.only_simulate:
198
278
  self.temp_cmd = command + "\r"
199
279
 
200
- if "~" in self.temp_cmd:
201
- # remove ~ in self.temp_cmd
202
- self.temp_cmd = self.temp_cmd[1:]
203
- else:
204
- self.usedSendQueue.put(self.temp_cmd)
205
280
  if self.ser is not None or not self.only_simulate:
206
- self.temp_cmd += "\r"
207
281
  self.ser.write(self.temp_cmd.encode("ascii"))
208
282
  if self.is_log_message:
209
283
  print(
@@ -213,249 +287,107 @@ class MoonsStepper(Subject):
213
287
  else:
214
288
  print(f"Target device is not opened. Command: {command}")
215
289
 
216
- def read(self, timeout=1):
217
- if self.ser is not None and self.ser.is_open:
218
- print("reading...")
219
- try:
220
- start_time = time.time()
221
- while time.time() - start_time < timeout:
222
- if self.ser.in_waiting > 0:
223
- response = self.ser.read(self.ser.in_waiting)
224
- response = response.decode("utf-8").strip()
225
- if self.is_log_message:
226
- print(
227
- f"[bold blue]Recv from {self.device} :[/bold blue] {response}"
228
- )
229
- return response
230
- time.sleep(0.01)
231
- print("reading timeout")
232
- return None
233
- except Exception as e:
234
- print(f"Error when reading serial port: {str(e)}")
235
- return None
236
- elif self.only_simulate:
237
- simulated_response = "simulate response"
238
- if self.is_log_message:
239
- print(
240
- f"[bold blue]Recv from simulate device:[/bold blue] {simulated_response}"
241
- )
242
- return simulated_response
290
+ def send_command(self, address="", command="", value=None):
291
+ if command == "":
292
+ print("Command can't be empty")
293
+ return
294
+ if value is not None:
295
+ command = self.addressed_cmd(address, command + str(value))
296
+ else:
297
+ command = self.addressed_cmd(address, command)
298
+
299
+ self.sendQueue.put_nowait(command)
300
+
301
+ def update(self):
302
+
303
+ while self.is_updating:
304
+ if self.ser is not None:
305
+ if self.ser.in_waiting > 0:
306
+ response = self.ser.read(self.ser.in_waiting)
307
+ response = response.decode("ascii", errors="ignore").strip()
308
+ response = response.split("\r")
309
+
310
+ for r in response:
311
+ if r != "":
312
+ self.readBuffer += r
313
+ self.handle_recv(r)
314
+
315
+ if self.sendQueue.empty() != True:
316
+ # time.sleep(
317
+ # 0.02
318
+ # ) # Time for RS485 converter to switch between Transmit and Receive mode
319
+ while not self.sendQueue.empty():
320
+ # time.sleep(
321
+ # 0.05
322
+ # ) # Time for RS485 converter to switch between Transmit and Receive mode
323
+ cmd = self.sendQueue.get_nowait()
324
+ self.send(cmd)
325
+ self.sendQueue.task_done()
326
+
327
+ def handle_recv(self, response):
328
+ if "*" in response:
329
+ print(f"[bold green](o)buffered_ack[/bold green]")
330
+ elif "%" in response:
331
+ print(f"[bold green](v)success_ack[/bold green]")
332
+ elif "?" in response:
333
+ print(f"[bold red](x)fail_ack[/bold red]")
243
334
  else:
244
- print("Device not open, read fail.")
245
- return None
335
+ print(f"[bold blue]Received from {self.device}: [/bold blue]", response)
336
+ self.recvQueue.put_nowait(response)
337
+
338
+ if "=" in response:
339
+ callback = self.pending_callbacks.get_nowait()
340
+ if callback:
341
+ callback(response)
342
+ # for command, callback in list(self.pending_callbacks.items()):
343
+ # if command in response:
344
+ # if callback:
345
+ # callback(response)
346
+ # del self.pending_callbacks[command]
347
+ # break
246
348
 
247
349
  # endregion
248
350
 
249
351
  # region motor motion functions
250
- def enable(self, motor_address="", enable=True):
251
- cmd = "ME" if enable else "MD"
252
- self.send(self.addressed_cmd(motor_address, cmd))
253
-
254
- def move_absolute(self, motor_address="", position=0, speed=0.15):
255
- self.send(self.addressed_cmd(motor_address, f"VE{speed}"))
256
- self.send(self.addressed_cmd(motor_address, f"FP{position}"))
257
352
 
258
- def move_fixed_distance(self, motor_address="", distance=100, speed=0.15):
259
- self.send(self.addressed_cmd(motor_address, "VE{}".format(speed)))
260
- self.send(self.addressed_cmd(motor_address, "FL{}".format(int(distance))))
261
-
262
- def start_jog(self, motor_address="", speed=0.15, direction="CW"):
263
- self.send(self.addressed_cmd(motor_address, "JS{}".format(speed)))
264
- time.sleep(0.01)
265
- self.send(self.addressed_cmd(motor_address, "CJ"))
266
- # self.send(self.addressed_cmd(motor_address, "CS{}".format(speed)))
267
-
268
- def change_jog_speed(self, motor_address="", speed=0.15):
269
- self.send(self.addressed_cmd(motor_address, "CS{}".format(speed)))
270
-
271
- def stop_jog(self, motor_address=""):
272
- self.send(self.addressed_cmd(motor_address, "SJ"))
273
-
274
- def stop(self, motor_address=""):
275
- self.send(self.addressed_cmd(motor_address, "ST"))
276
-
277
- def stop_with_deceleration(self, motor_address=""):
278
- self.send(self.addressed_cmd(motor_address, "STD"))
279
-
280
- def stop_and_kill(self, motor_address="", with_deceleration=True):
281
- if with_deceleration:
282
- self.send(self.addressed_cmd(motor_address, "SKD"))
283
- else:
284
- self.send(self.addressed_cmd(motor_address, "SK"))
285
-
286
- def setup_motor(self, motor_address="", kill=False):
287
- if kill:
288
- self.stop_and_kill(motor_address)
289
- self.set_transmit_delay(motor_address, 25)
290
- self.set_return_format_dexcimal(motor_address)
291
-
292
- def calibrate(self, motor_address="", speed=0.3, onStart=None, onComplete=None):
293
- self.send(self.addressed_cmd(motor_address, "VE{}".format(speed)))
294
- # time.sleep(0.01)
295
- # self.send(self.addressed_cmd(motor_address, "DI10"))
296
- # time.sleep(0.01)
297
- self.send(self.addressed_cmd(motor_address, "SH3F"))
298
- # time.sleep(0.01)
299
- self.send(self.addressed_cmd(motor_address, "EP0"))
300
- # time.sleep(0.01)
301
- self.send(self.addressed_cmd(motor_address, "SP0"))
302
-
303
- def alarm_reset(self, motor_address=""):
304
- self.send(self.addressed_cmd(motor_address, "AR"))
305
-
306
- # speed slow= 0.25, medium=1, fast=5
307
- def set_transmit_delay(self, motor_address="", delay=15):
308
- self.send(self.addressed_cmd(motor_address, "TD{}".format(delay)))
353
+ # def setup_motor(self, motor_address="", kill=False):
354
+ # if kill:
355
+ # self.stop_and_kill(motor_address)
356
+ # self.set_transmit_delay(motor_address, 25)
357
+ # self.set_return_format_dexcimal(motor_address)
309
358
 
310
- # endregion
311
-
312
- # region motor status functions
313
- def get_position(self, motor_address):
314
- self.send(self.addressed_cmd(motor_address, "IP"))
315
- return self.read()
316
- # self.new_value_event.wait(timeout=0.5)
317
- # return self.get_value()
318
-
319
- def get_temperature(self, motor_address):
320
- self.send(self.addressed_cmd(motor_address, "IT"))
321
- # self.new_value_event.wait(timeout=0.5)
322
- return self.read()
323
- # return int(self.get_value()) / 10
324
-
325
- def get_sensor_status(self, motor_address):
326
- self.send(self.addressed_cmd(motor_address, "IS"))
327
- return self.read()
328
- # self.new_value_event.wait(timeout=0.5)
329
- # return self.get_value()
330
-
331
- def get_votalge(self, motor_address):
332
- self.send(self.addressed_cmd(motor_address, "IU"))
333
- return self.read()
334
- # self.new_value_event.wait(timeout=0.5)
335
- # return self.get_value()
336
-
337
- def get_acceleration(self, motor_address):
338
- self.send(self.addressed_cmd(motor_address, "AC"))
339
- return self.read()
340
- # self.new_value_event.wait(timeout=0.5)
341
- # return self.get_value()
342
-
343
- def get_deceleration(self, motor_address):
344
- self.send(self.addressed_cmd(motor_address, "DE"))
345
- return self.read()
346
- # self.new_value_event.wait(timeout=0.5)
347
- # return self.get_value()
348
-
349
- def get_velocity(self, motor_address):
350
- self.send(self.addressed_cmd(motor_address, "VE"))
351
- return self.read()
352
- # self.new_value_event.wait(timeout=0.5)
353
- # return self.get_value()
354
-
355
- def get_distance(self, motor_address):
356
- self.send(self.addressed_cmd(motor_address, "DI"))
357
- return self.read()
358
- # self.new_value_event.wait(timeout=0.5)
359
- # return self.get_value()
360
-
361
- def get_jog_speed(self, motor_address):
362
- self.send(self.addressed_cmd(motor_address, "JS"))
363
- # self.new_value_event.wait(timeout=0.5)
364
- # return self.get_value()
365
- return self.read()
366
-
367
- def get_info(self, motor_address, progress=None):
368
- self.set_return_format_dexcimal(motor_address)
369
- self.motor_wait(motor_address, 0.1)
370
- totalInfoCount = 7
371
- pos = self.extractValueFromResponse(self.get_position(motor_address))
372
- if progress:
373
- progress(round(1 / totalInfoCount, 1))
374
- temp = (
375
- int(self.extractValueFromResponse(self.get_temperature(motor_address))) / 10
359
+ def home(self, motor_address="", speed=0.3, onComplete=None):
360
+ self.send_command(
361
+ address=motor_address, command=StepperCommand.VELOCITY, value=speed
376
362
  )
377
- if progress:
378
- progress(round(2 / totalInfoCount, 1))
379
- vol = int(self.extractValueFromResponse(self.get_votalge(motor_address))) / 10
380
- if progress:
381
- progress(round(3 / totalInfoCount, 1))
382
- accel = self.extractValueFromResponse(self.get_acceleration(motor_address))
383
- if progress:
384
- progress(round(4 / totalInfoCount, 1))
385
- decel = self.extractValueFromResponse(self.get_deceleration(motor_address))
386
- if progress:
387
- progress(round(5 / totalInfoCount, 1))
388
- jogsp = self.extractValueFromResponse(self.get_jog_speed(motor_address))
389
- if progress:
390
- progress(round(6 / totalInfoCount, 1))
391
- info = {
392
- "pos": pos,
393
- "temp": temp,
394
- "vol": vol,
395
- "accel": accel,
396
- "decel": decel,
397
- "jogsp": jogsp,
398
- }
399
- if progress:
400
- progress(round(7 / totalInfoCount))
401
-
402
- return info
403
-
404
- def get_status(self, motor_address) -> str:
405
- self.set_return_format_dexcimal(motor_address)
406
- self.send(self.addressed_cmd(motor_address, "RS"))
407
- self.new_value_event.wait(timeout=0.5)
408
- return str(self.get_value())
409
-
410
- def set_return_format_dexcimal(self, motor_address):
411
- self.send(self.addressed_cmd(motor_address, "IFD"))
363
+ self.send_command(
364
+ address=motor_address, command=StepperCommand.HOME, value="3F"
365
+ )
366
+ self.send_command(
367
+ address=motor_address, command=StepperCommand.ENCODER_POSITION
368
+ )
369
+ self.send_command(
370
+ address=motor_address, command=StepperCommand.SET_POSITION, value=0
371
+ )
372
+ if onComplete:
373
+ self.get_status(
374
+ motor_address, StepperCommand.SET_POSITION, callback=onComplete
375
+ )
412
376
 
413
- def set_return_format_hexdecimal(self, motor_address):
414
- self.send(self.addressed_cmd(motor_address, "IFH"))
377
+ # endregion
378
+ def get_status(self, motor_address, command: StepperCommand, callback=None):
379
+ command = self.addressed_cmd(motor_address, command)
380
+ if callback:
381
+ self.pending_callbacks.put_nowait(callback)
382
+ self.sendQueue.put_nowait(command)
415
383
 
416
384
  # endregion
417
385
 
418
386
  # region utility functions
419
- def motor_wait(self, motor_address, wait_time):
420
- self.send(self.addressed_cmd(motor_address, "WT{}".format(wait_time)))
421
387
 
422
388
  def addressed_cmd(self, motor_address, command):
423
- if motor_address == "":
424
- return f"~{command}"
425
389
  return f"{motor_address}{command}"
426
390
 
427
- def extractValueFromResponse(self, response):
428
- pattern = r"=(.*)"
429
- if response == None:
430
- return None
431
- result = re.search(pattern, response)
432
- if result:
433
- return result.group(1)
434
- else:
435
- return None
436
-
437
- def get_value(self):
438
- print("Waiting for value")
439
- self.new_data_event.wait(timeout=0.5)
440
- print("Recv:" + self.listeningBufferPre)
441
- self.new_data_event.clear()
442
- return self.listeningBufferPre
443
- # if "%" in self.listeningBufferPre:
444
- # return "success_ack"
445
- # if "?" in self.listeningBufferPre:
446
- # return "fail_ack"
447
- # if "*" in self.listeningBufferPre:
448
- # return "buffered_ack"
449
- # self.new_value_event.set()
450
- # pattern = r"=(\w+(?:\.\w+)?|\d+(?:\.\d+)?)"
451
- # result = re.search(pattern, self.listeningBufferPre)
452
- # self.listeningBufferPre = ""
453
- # self.new_value_event.clear()
454
- # if result:
455
- # return result.group(1)
456
- # else:
457
- # return "No_value_found"
458
-
459
391
 
460
392
  # endregion
461
393
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: moons_motor
3
- Version: 0.0.11
3
+ Version: 0.1.3
4
4
  Summary: This is a python library for controlling the Moons' motor through the serial port.
5
5
  Author-email: miroc <mike8503111@gmail.com>
6
6
  Project-URL: Repository, https://github.com/miroc99/moons_motor.git
@@ -16,6 +16,7 @@ Requires-Dist: pyserial
16
16
  Requires-Dist: rich
17
17
  Requires-Dist: python-socketio
18
18
  Requires-Dist: requests
19
+ Dynamic: license-file
19
20
 
20
21
  # Moons Motor
21
22
 
@@ -0,0 +1,11 @@
1
+ moons_motor/__init__.py,sha256=qOpsRwizV-DpKSvNzyvj8ju3cs6vwgIICur1Oe6sxOA,27
2
+ moons_motor/motor.py,sha256=rpunJXViqvSpMW9uRJDctBPyfSJnZh5WZtBtci16-Ck,13308
3
+ moons_motor/observer.py,sha256=PXzuPYKRb2HpjArJcD8HakYIPfFGAs1uBDIL8PSizgA,124
4
+ moons_motor/simulate.py,sha256=J0y1fZhoOim9i-BAkprxnPern1SAdkDfKPqT2MWyDwU,2561
5
+ moons_motor/status.py,sha256=jXQZFZTt9ugHktkWKLII8MpEQQaeO-UjlwTrrP4LJNE,2872
6
+ moons_motor/subject.py,sha256=L_GS6fvJTeX7X23o3T92oiZ4rtLVKA2OEd9GpHn_Dz4,445
7
+ moons_motor-0.1.3.dist-info/licenses/LICENSE,sha256=nsYjO800SjIjI85y2kVHR5mC3tca2vs4kK_BhNe89bM,1074
8
+ moons_motor-0.1.3.dist-info/METADATA,sha256=Zaj25TLKPvBv0qJWRInaALURr8bcOtDLNWfxQymFdtY,1304
9
+ moons_motor-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ moons_motor-0.1.3.dist-info/top_level.txt,sha256=0dE-CR5_NYBw34jHIDGQNWpMllzO6mtUIuKyRv_rJLg,12
11
+ moons_motor-0.1.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,11 +0,0 @@
1
- moons_motor/__init__.py,sha256=qOpsRwizV-DpKSvNzyvj8ju3cs6vwgIICur1Oe6sxOA,27
2
- moons_motor/motor.py,sha256=Fbp08XMgAjLiyGqFD-WXsGXBNrgCiclsopYxT0tq9Xk,16077
3
- moons_motor/observer.py,sha256=PXzuPYKRb2HpjArJcD8HakYIPfFGAs1uBDIL8PSizgA,124
4
- moons_motor/simulate.py,sha256=J0y1fZhoOim9i-BAkprxnPern1SAdkDfKPqT2MWyDwU,2561
5
- moons_motor/status.py,sha256=jXQZFZTt9ugHktkWKLII8MpEQQaeO-UjlwTrrP4LJNE,2872
6
- moons_motor/subject.py,sha256=L_GS6fvJTeX7X23o3T92oiZ4rtLVKA2OEd9GpHn_Dz4,445
7
- moons_motor-0.0.11.dist-info/LICENSE,sha256=nsYjO800SjIjI85y2kVHR5mC3tca2vs4kK_BhNe89bM,1074
8
- moons_motor-0.0.11.dist-info/METADATA,sha256=Pde70Xqjwl4hZmQZMig8ik6_T1XqutMWs5wkkAkTVdg,1282
9
- moons_motor-0.0.11.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
10
- moons_motor-0.0.11.dist-info/top_level.txt,sha256=0dE-CR5_NYBw34jHIDGQNWpMllzO6mtUIuKyRv_rJLg,12
11
- moons_motor-0.0.11.dist-info/RECORD,,