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

Fix scanner IP address binding when netifaces/psutil are not available #519

Merged
merged 6 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 14 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ TinyTuya can also connect to the Tuya Cloud to poll status and issue commands to
# Example Usage of TinyTuya
import tinytuya

d = tinytuya.OutletDevice('DEVICE_ID_HERE', 'IP_ADDRESS_HERE', 'LOCAL_KEY_HERE')
d.set_version(3.3)
d = tinytuya.Device('DEVICE_ID_HERE', 'IP_ADDRESS_HERE', 'LOCAL_KEY_HERE', version=3.3)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good with that too...

data = d.status()
print('Device status: %r' % data)
```
Expand Down Expand Up @@ -276,8 +275,7 @@ import tinytuya
"""
OUTLET Device
"""
d = tinytuya.OutletDevice('DEVICE_ID_HERE', 'IP_ADDRESS_HERE', 'LOCAL_KEY_HERE')
d.set_version(3.3)
d = tinytuya.Device('DEVICE_ID_HERE', 'IP_ADDRESS_HERE', 'LOCAL_KEY_HERE', version=3.3)
data = d.status()

# Show status and state of first controlled switch on device
Expand Down Expand Up @@ -342,34 +340,31 @@ You can set up a persistent connection to a device and then monitor the state ch
```python
import tinytuya

d = tinytuya.OutletDevice('DEVICEID', 'DEVICEIP', 'DEVICEKEY')
d.set_version(3.3)
d.set_socketPersistent(True)
d = tinytuya.OutletDevice('DEVICEID', 'DEVICEIP', 'DEVICEKEY', version=3.3, persist=True)

print(" > Send Request for Status < ")
payload = d.generate_payload(tinytuya.DP_QUERY)
d.send(payload)
d.status(nowait=True)

print(" > Begin Monitor Loop <")
while(True):
# See if any data is available
data = d.receive()
print('Received Payload: %r' % data)

# Send keyalive heartbeat
print(" > Send Heartbeat Ping < ")
payload = d.generate_payload(tinytuya.HEART_BEAT)
d.send(payload)
# Send keep-alive heartbeat
if not data:
print(" > Send Heartbeat Ping < ")
d.heartbeat()

# NOTE If you are not seeing updates, you can force them - uncomment:
# print(" > Send Request for Status < ")
# payload = d.generate_payload(tinytuya.DP_QUERY)
# d.send(payload)
# d.status(nowait=True)

# NOTE Some smart plugs require an UPDATEDPS command to update power data
# print(" > Send DPS Update Request < ")
# payload = d.generate_payload(tinytuya.UPDATEDPS)
# d.send(payload)

```

### Tuya Cloud Access
Expand Down Expand Up @@ -565,9 +560,9 @@ In addition to the built-in `OutletDevice`, `BulbDevice` and `CoverDevice` devic

```python
# Example usage of community contributed device modules
from tinytuya import Contrib
from tinytuya.Contrib import ThermostatDevice

thermo = Contrib.ThermostatDevice( 'abcdefghijklmnop123456', '172.28.321.475', '1234567890123abc' )
thermo = ThermostatDevice( 'abcdefghijklmnop123456', '172.28.321.475', '1234567890123abc' )
```

## Tuya Data Points - DPS Table
Expand Down Expand Up @@ -869,9 +864,9 @@ NOTE (*) - Depending on the firmware, either 18/19/20/26/27 or 108/109/110/111/x
A user contributed module is available for this device in the [Contrib library](https://github.com/jasonacox/tinytuya/tree/master/tinytuya/Contrib):

```python
from tinytuya import Contrib
from tinytuya.Contrib import ThermostatDevice

thermo = Contrib.ThermostatDevice( 'abcdefghijklmnop123456', '172.28.321.475', '1234567890123abc' )
thermo = ThermostatDevice( 'abcdefghijklmnop123456', '172.28.321.475', '1234567890123abc' )
```

For info on the Sensor Data lists, see https://github.com/jasonacox/tinytuya/discussions/139
Expand Down
4 changes: 4 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# RELEASE NOTES

## v1.15.1 - Scanner Fixes

* Fix scanner broadcast attempting to bind to the wrong IP address, introduced in v1.15.0

## v1.15.0 - Scanner Fixes

* Fix force-scanning bug in scanner introduced in last release and add broadcast request feature to help discover Tuya version 3.5 devices by @uzlonewolf in https://github.com/jasonacox/tinytuya/pull/511.
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
cryptography>=3.1 # Encryption - AES can also be provided via PyCryptodome or pyaes or pyca/cryptography
requests # Used for Setup Wizard - Tuya IoT Platform calls
colorama # Makes ANSI escape character sequences work under MS Windows.
netifaces # Used to get the IP address of the local machine for scanning for devices.
#netifaces # Used to get the IP address of the local machine for scanning for devices, mainly useful for multi-interface machines.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
INSTALL_REQUIRES = [
'requests', # Used for Setup Wizard - Tuya IoT Platform calls
'colorama', # Makes ANSI escape character sequences work under MS Windows.
'netifaces', # Used for device discovery
#'netifaces', # Used for device discovery, mainly required on multi-interface machines
]

CHOOSE_CRYPTO_LIB = [
Expand Down
2 changes: 1 addition & 1 deletion tinytuya/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
# Colorama terminal color capability for all platforms
init()

version_tuple = (1, 15, 0)
version_tuple = (1, 15, 1)
version = __version__ = "%d.%d.%d" % version_tuple
__author__ = "jasonacox"

Expand Down
17 changes: 12 additions & 5 deletions tinytuya/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,16 @@
log = logging.getLogger(__name__)

# Helper Functions
def getmyIP():
def getmyIPaddr():
# Fetch my IP address and assume /24 network
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
r = s.getsockname()[0]
r = str(s.getsockname()[0])
s.close()
r = str(r).split('.')
return r

def getmyIP():
r = getmyIPaddr().split('.')
# assume a /24 network
return '%s.%s.%s.0/24' % tuple(r[:3])

Expand Down Expand Up @@ -196,7 +199,7 @@ def get_ip_to_broadcast():
if ip_to_broadcast:
return ip_to_broadcast

ip_to_broadcast['255.255.255.255'] = getmyIP()
ip_to_broadcast['255.255.255.255'] = getmyIPaddr()
return ip_to_broadcast

def send_discovery_request( iface_list=None ):
Expand All @@ -215,7 +218,11 @@ def send_discovery_request( iface_list=None ):
if 'socket' not in iface:
iface['socket'] = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
iface['socket'].setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
iface['socket'].bind( (address,0) )
try:
iface['socket'].bind( (address,0) )
except:
log.debug( 'Failed to bind to address %r for discovery broadcasts, skipping interface!', address, exc_info=True )
continue

if 'payload' not in iface:
bcast = json.dumps( {"from":"app","ip":address} ).encode()
Expand Down
Loading