Skip to content

Commit

Permalink
Merge pull request #519 from uzlonewolf/forcescan-fix-2
Browse files Browse the repository at this point in the history
Fix scanner IP address binding when netifaces/psutil are not available
  • Loading branch information
jasonacox authored Jul 20, 2024
2 parents 2b84315 + 62c9ad4 commit 0cae224
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 27 deletions.
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)
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

0 comments on commit 0cae224

Please sign in to comment.