richibrics / IoTuring

Your Windows, Linux, macOS computer as MQTT and HomeAssistant integration
https://pypi.org/project/IoTuring/
GNU General Public License v3.0
82 stars 6 forks source link

Wifi Entity for Windows #89

Open lockenkop opened 11 months ago

lockenkop commented 11 months ago

I saw the network entity lingering in ToImplement and while wokring on that did the wifi entity first, since this was the original functionality of the network entity.

Options for configuration:

EntityState

ExtraAttributes

Multiple Instances:

Configuration:

Windows: image

Linux: image

Edgecases: If some Information is not available it is not shown: (behaviour is the same on all OS) image

infeeeee commented 10 months ago

@lockenkop I added a commit where I moved RunCommand to OsD. Now you can call OsD.Runcommand("iwconfig something") in CheckSystemSupport.

I didn't check what you messed up, but exiting with ctrl+C doesn't work :) now, and logging is strange. Maybe create a new branch and PR from main without fanspeed and other changes, and just cherrypick the good commits.

lockenkop commented 10 months ago

I reduced the envelope to t he Wifi entity in order to get this PR done. Functionally everything should be in place. I'll have to do some refactoring to get it more readability.

richibrics commented 10 months ago

@infeeeee @lockenkop which is the standard way of showing extra attributes with missing data in HAss ? "Not available" or just avoid showing the attribute ?

lockenkop commented 10 months ago

The HAss IOS companion App reports "N/A" Although most could just not send the attributes if not available. Meaning: no attribute == not available

lockenkop commented 10 months ago

Since we not really came to a conclusion on what we do with not available attributes i made ic onfigurable, defaulting to hiding not available attributes. image I'll have to take a general scan over all the code and a quick test under windows for the latest changes. Other than that tomorrow it'll be good to go from me!

richibrics commented 10 months ago

About this, I think we should decide one of the two so to keep the standard also for other entities. I'd say to remove the extra attributes directly since even if the user notices they are missing, he can't do anything to have them working properly. I also think that the configuration option may confuse the user that doesn't know which one is better for him. What do you guys think ? @lockenkop @infeeeee

richibrics commented 10 months ago

In my macOS version (BigSur, 11.7.8) I didn't have the airport util in my path. I had to type sudo ln -s /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport /usr/local/bin/airport in order to get it. We'll need to add this in the documentation.

lockenkop commented 10 months ago

I saw that most online macos airport tutorials had the full path called. Linking it onto path seems to be the best solution.

Regarding showing missing entities, looking at my hass and my usage over the last years it makes for a more tidy experience not showing "not available" entities. Although we should create our own documentation what "could" be there if it were be found.

richibrics commented 10 months ago

Yes I agree with setting the full path in the command

richibrics commented 10 months ago

We need to find a way to define a different unit for different OS in Hass: % if Windows, dBm otherwise. It would be simpler to convert the value from % to dBm for windows too

lockenkop commented 10 months ago

@infeeeee suggested to have a look at https://github.com/awkman/pywifi. They take a better approach on getting wifi information. They utilize the ctypes module and directly communicate with windows apis. This apporach is very powerfull but needs alot of boilerplate. The only elegant way i see, is to include this dependency. Changing locales on the fly is, as far as my research went, not possible.

infeeeee commented 10 months ago

The only elegant way i see, is to include this dependency.

I was also thinking about this, but that module seems not really maintained, last commit was 5 years ago, the maintainer hasn't done anything on Github since 2019. And it has a lot of features we don't need (e.g. it can connect to network). So using this as a dependency would be a bit risky and overkill.

We already use ctypes in other entities. The license of pywifi is more lax, so you can copy paste code from there.

On linux I played a bit with it. We should use iw for this, as iwconfig is part of the wireless-tools package, and that's deprecated. Here is the official docs how to replace iwconfig commands with iw: https://wireless.wiki.kernel.org/en/users/Documentation/iw/replace-iwconfig And I also found that on linux the output is always in English, regardless of the language of the system, so you shouldn't check the language there, so it's already solved. iw documentation

lockenkop commented 10 months ago

as i was fiddling around wit pywifi i came to the same conclusion. Pywifi itself is built upon https://github.com/6e726d/PyWiWi (same boilerplate for ctypes etc.). I'll try to get a minimum working example going.

The change to iw looks pretty straightforward, having no locales to worry about is also a +.

lockenkop commented 10 months ago

I got a necessary minimum copied from PyWifi. Getting all wifi interfaces works. Querying an interface for its status (connected, connecting, disconnected, etc. ) works.

    def status(self, obj):
        """Get the wifi interface status."""

        data_size = DWORD()
        data = PDWORD()
        opcode_value_type = DWORD()
        self._wlan_query_interface(self._handle, obj['guid'], 6,
                                   byref(data_size), byref(data),
                                   byref(opcode_value_type))

        return status_dict[data.contents.value]

image 4

# Define interface status.
IFACE_DISCONNECTED = 0
IFACE_SCANNING = 1
IFACE_INACTIVE = 2
IFACE_CONNECTING = 3
IFACE_CONNECTED = 4

Querying for its rssi is giving me a headache though, my very basic c knowledge is keeping me back understanding this approach and microsofts docs. https://learn.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlanqueryinterface

Keeping close to PyWifis usage above

    def rssi(self, obj):
        """Get the wifi interface status."""

        data_size = PDWORD()
        data = LONG()
        opcode_value_type = DWORD()
        self._wlan_query_interface(self._handle, obj['guid'], 23,
                                   byref(data_size), byref(data),
                                   byref(opcode_value_type))

        return data.contents.value

changing the opcode from 6 to 23 Guessing with this enum doc https://learn.microsoft.com/en-us/windows/win32/api/wlanapi/ne-wlanapi-wlan_intf_opcode-r1

This presents the following output in data.contents: image image I'm stuck there, i fiddled around with datatypes and other different opcodes. I couldn't make the most sense of what i was doing and i was just guessing.

I pushed my test script if anyone wants to take a look.

lockenkop commented 8 months ago

I'll have to drop windows support if it has to be done by calling windows apis directly. That stuff just flies right over my head.

@richibrics shall I refactor Linux and mac support into another pr? This way the beginning of the windows implementation will just remain her for someone to pickup on.

richibrics commented 8 months ago

Yes sounds great, I will make it working on Windows in the future