Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asyncio Testing #60

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft

Asyncio Testing #60

wants to merge 9 commits into from

Conversation

odwdinc
Copy link
Owner

@odwdinc odwdinc commented Oct 24, 2020

Not shure if this is the right direction or not thoughts?

Not shure if this is the right derection or not thoughts?
_attemps is depercataed
@odwdinc odwdinc requested a review from hankhank10 October 24, 2020 22:25
@danricho
Copy link

I like the idea of asyncio in principal, but I haven't tested it as I'm away from home (and hence the Sim).
Does it mean that the "time" and "attemp" parameters will no longer be necessary?

@odwdinc odwdinc marked this pull request as draft October 25, 2020 16:01
@odwdinc
Copy link
Owner Author

odwdinc commented Oct 25, 2020

@danricho just thinking about removing attempts,
not 100% on this so left in the pluming for now.
values are set on thread

self.timerThread = threading.Thread(target=self._run)
self.timerThread.daemon = True
self.timerThread.start()

_run

def _run(self):
while self.quit == 0:
self.dll.CallDispatch(self.hSimConnect, self.my_dispatch_proc_rd, None)
time.sleep(.002)

Data is revived by

async def get_return_data(self, _Request):
while _Request.outData is None:
await asyncio.sleep(0.01)
async def get_data(self, _Request):
self.request_data(_Request)
await self.get_return_data(_Request)

normally attempts are check in the while loop (Line 244) to escape if data is not received in a given time. I don't know if this is still needed or wanted with the new async bits.

With time, it is how long to return cashed data vs new data form the sim.

@property
async def value(self):
if self._deff_test():
# self.sm.run()
if (self.LastData + self.time) < millis():
await self.sm.get_data(self)
self.LastData = millis()
return self.outData
else:
raise Exception(self.definitions[0][0])

@viboux
Copy link

viboux commented Oct 26, 2020

Just tested this last version of the asyncio branch for a good 45 min reading altitude/long/lat/baro with another instance giving command and so far very stable and received no None value.

@daheise
Copy link
Contributor

daheise commented Nov 6, 2020

I haven't tested this PR, but I was just considering writing an async wrapper around my calls to Python-SimConnect so I hit fewer cases of needing to handle a None, so I think aync support is a good direction.

@danricho
Copy link

I tested this change this morning and have found it flawless.

It enabled me to log flight parameters at a much higher frequency than the old method which essentially hangs until a value is received.

Only limitation I found is the returning of 'None's when I used get() on signals with an index (eg: 'x:1') or the wind direction/speed. But I used request in setup then .value() in the main loop to get around this. I didn't figure out why this happened.

@odwdinc
Copy link
Owner Author

odwdinc commented Nov 15, 2020

so with such a big change how should we make handle the move?
I have been holding off to see if I can think of some way..

@odwdinc
Copy link
Owner Author

odwdinc commented Nov 15, 2020

new sample, added an a to the async vertions of functions to keep backwords code woking.

async def avalue(self):

Sample:

from SimConnect import *
import logging
from SimConnect.Enum import *
from time import sleep
import asyncio

logging.basicConfig(level=logging.DEBUG)
LOGGER = logging.getLogger(__name__)
LOGGER.info("START")

# creat simconnection and pass used user classes
sm = SimConnect()
aq = AircraftRequests(sm, _time=10, _attemps=10)
Throttle = aq.find('GENERAL_ENG_THROTTLE_LEVER_POSITION:1')


# none async Function still works
print("Throttle:", Throttle.value)
print("Alt=%f Lat=%f Lon=%f Kohlsman=%.2f" % (
	aq.PositionandSpeedData.get('PLANE_ALTITUDE'),
	aq.PositionandSpeedData.get('PLANE_LATITUDE'),
	aq.PositionandSpeedData.get('PLANE_LONGITUDE'),
	aq.FlightInstrumentationData.get('KOHLSMAN_SETTING_HG')
))


# New async Function
async def PrintData():
	# THROTTLE Request
	print("Throttle:", await Throttle.avalue)
	print("Lat=%f Lon=%f Alt=%f Kohlsman=%.2f" % tuple(
		await asyncio.gather(
			aq.PositionandSpeedData.aget('PLANE_LATITUDE'),
			aq.PositionandSpeedData.aget('PLANE_LONGITUDE'),
			aq.PositionandSpeedData.aget('PLANE_ALTITUDE'),
			aq.FlightInstrumentationData.aget('KOHLSMAN_SETTING_HG')
		)
	))

asyncio.run(PrintData())

sm.exit()
quit()

@daheise
Copy link
Contributor

daheise commented Nov 15, 2020

My opinion: Follow semantic versioning. If this is a breaking change to old code, increment the major version number. It's on us as library users if we failed to pin the version correctly.

Unless there's a good reason to maintain both versions of the functions, don't.

@danricho
Copy link

I do agree that library users should be managing library versions and that we shouldn't keep both versions side by side due to maintenance burden; however I have a few thoughts that might help or at least ease the transition:

  • could we call the non-async versions from within the async version so only the core functions nee to be maintained, or
  • could we add a deprecated feedback message in the non-async version, with an end-of-support point defined?

I only suggest this as there seems to be quite a number of users now.
Just my 2 cents!

@mracko
Copy link

mracko commented Nov 16, 2020

I'd like to report the following bug I've noticed:

The asyncio version doesn't work when getting two SimVars with the same key but different index consecutively. Example:

ui_friendly_dictionary["NAV1_OBS_DEG"] = round(await aq.get("NAV_OBS:1"),0)
ui_friendly_dictionary["NAV2_OBS_DEG"] = round(await aq.get("NAV_OBS:2"),0)

NAV2_OBS_DEG will be getting the NAV_OBS:1 value.

The code works, however, when I introduce a different key inbetween. Like this:

ui_friendly_dictionary["NAV1_OBS_DEG"] = round(await aq.get("NAV_OBS:1"),0)
ui_friendly_dictionary["ADF_CARD_DEG"] = round(await aq.get("ADF_CARD"),0)
ui_friendly_dictionary["NAV2_OBS_DEG"] = round(await aq.get("NAV_OBS:2"),0)

This issue has been introduced with asyncio version and hasn't been a problem before. I'm not sure if it's a problem on my part or it's a bug in general. Unfortunately, my Python skills aren't up to the skills to propose a bug fix.

Thanks!

@danricho
Copy link

danricho commented Nov 16, 2020

Hi @mracko, I'd suggest checking the thread in issue #67. I had a similar issue, albeit no with the Asyncio version.

It may or may not be useful, but I thought I'd share and I hope it's useful.

Cheers.

@mracko
Copy link

mracko commented Nov 16, 2020

Thanks @danricho. This seems to explain the behavior and I understand the performance reasons. Hopefully, I'll be able to come up with a solution on how to efficiently get the NAV OBSs myself. Again, I'm not a Python pro. :)

@danricho
Copy link

If you post your code, I or someone else could help you adjust it to get this working.
;)

@Koseng
Copy link
Contributor

Koseng commented Jun 3, 2021

Hi guys,

let's go async ;-)
See #98 for introducing asyncio, including a sync wrapper to stay compatible.

Please test.
In a next step code can be ported to async, and async examples can be added.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants