794 str(r.ipv4_subnet) if r.ipv4_subnet else'0.0.0.0', |
794 str(r.ipv4_subnet) if r.ipv4_subnet else'0.0.0.0', |
795 str(r.ipv4_gateway) if r.ipv4_gateway else'0.0.0.0', |
795 str(r.ipv4_gateway) if r.ipv4_gateway else'0.0.0.0', |
796 str(r.ipv4_dns) if r.ipv4_dns else'0.0.0.0', |
796 str(r.ipv4_dns) if r.ipv4_dns else'0.0.0.0', |
797 ), |
797 ), |
798 'mac': binascii.hexlify(r.mac_address, ':').decode(), |
798 'mac': binascii.hexlify(r.mac_address, ':').decode(), |
799 'hostname': r.hostname, |
|
800 } |
799 } |
801 try: |
800 try: |
802 station['txpower'] = r.tx_power |
801 station['txpower'] = r.tx_power |
803 except AttributeError: |
802 except AttributeError: |
804 pass |
803 pass |
829 str(r.ipv4_subnet_ap) if r.ipv4_subnet_ap else'0.0.0.0', |
828 str(r.ipv4_subnet_ap) if r.ipv4_subnet_ap else'0.0.0.0', |
830 str(r.ipv4_gateway_ap) if r.ipv4_gateway_ap else'0.0.0.0', |
829 str(r.ipv4_gateway_ap) if r.ipv4_gateway_ap else'0.0.0.0', |
831 str(r.ipv4_dns) if r.ipv4_dns else'0.0.0.0', |
830 str(r.ipv4_dns) if r.ipv4_dns else'0.0.0.0', |
832 ), |
831 ), |
833 'mac': binascii.hexlify(r.mac_address_ap, ':').decode(), |
832 'mac': binascii.hexlify(r.mac_address_ap, ':').decode(), |
834 'hostname': r.hostname, |
|
835 } |
833 } |
836 try: |
834 try: |
837 ap['txpower'] = r.tx_power |
835 ap['txpower'] = r.tx_power |
838 except AttributeError: |
836 except AttributeError: |
839 pass |
837 pass |
840 print(json.dumps(ap)) |
838 print(json.dumps(ap)) |
841 |
839 |
842 overall = { |
840 overall = { |
843 'active': r.enabled |
841 'active': r.enabled, |
|
842 'hostname': r.hostname, |
844 } |
843 } |
845 print(json.dumps(overall)) |
844 print(json.dumps(overall)) |
846 |
845 |
847 wifi_status() |
846 wifi_status() |
848 del wifi_status |
847 del wifi_status |
866 station["ap_security"] |
865 station["ap_security"] |
867 ) |
866 ) |
868 |
867 |
869 return station, ap, overall |
868 return station, ap, overall |
870 |
869 |
871 def connectWifi(self, ssid, password): |
870 def connectWifi(self, ssid, password, hostname): |
872 """ |
871 """ |
873 Public method to connect a device to a WiFi network. |
872 Public method to connect a device to a WiFi network. |
874 |
873 |
875 @param ssid name (SSID) of the WiFi network |
874 @param ssid name (SSID) of the WiFi network |
876 @type str |
875 @type str |
877 @param password password needed to connect |
876 @param password password needed to connect |
878 @type str |
877 @type str |
|
878 @param hostname host name of the device |
|
879 @type str |
879 @return tuple containing the connection status and an error string |
880 @return tuple containing the connection status and an error string |
880 @rtype tuple of (bool, str) |
881 @rtype tuple of (bool, str) |
881 """ |
882 """ |
882 command = """ |
883 command = """ |
883 def connect_wifi(ssid, password): |
884 def connect_wifi(ssid, password, hostname): |
884 import json |
885 import json |
885 import wifi |
886 import wifi |
886 |
887 |
887 r = wifi.radio |
888 r = wifi.radio |
888 try: |
889 try: |
|
890 if hostname: |
|
891 r.hostname = hostname |
889 r.start_station() |
892 r.start_station() |
890 r.connect(ssid, password) |
893 r.connect(ssid, password) |
891 status = 'connected' |
894 status = 'connected' |
892 except Exception as exc: |
895 except Exception as exc: |
893 status = str(exc) |
896 status = str(exc) |
894 |
897 |
895 print(json.dumps({{'connected': r.ipv4_address is not None, 'status': status}})) |
898 print(json.dumps({{'connected': r.ipv4_address is not None, 'status': status}})) |
896 |
899 |
897 connect_wifi({0}, {1}) |
900 connect_wifi({0}, {1}, {2}) |
898 del connect_wifi |
901 del connect_wifi |
899 """.format( |
902 """.format( |
900 repr(ssid), |
903 repr(ssid), |
901 repr(password if password else ""), |
904 repr(password if password else ""), |
|
905 repr(hostname), |
902 ) |
906 ) |
903 |
907 |
904 with EricOverrideCursor(): |
908 with EricOverrideCursor(): |
905 out, err = self.executeCommands( |
909 out, err = self.executeCommands( |
906 command, mode=self._submitMode, timeout=15000 |
910 command, mode=self._submitMode, timeout=15000 |
988 if err: |
992 if err: |
989 return False |
993 return False |
990 |
994 |
991 return out.strip() == b"True" |
995 return out.strip() == b"True" |
992 |
996 |
993 def writeCredentials(self, ssid, password): |
997 def writeCredentials(self, ssid, password, hostname, country): # noqa: U100 |
994 """ |
998 """ |
995 Public method to write the given credentials to the connected device and modify |
999 Public method to write the given credentials to the connected device and modify |
996 the start script to connect automatically. |
1000 the start script to connect automatically. |
997 |
1001 |
998 @param ssid SSID of the network to connect to |
1002 @param ssid SSID of the network to connect to |
999 @type str |
1003 @type str |
1000 @param password password needed to authenticate |
1004 @param password password needed to authenticate |
1001 @type str |
1005 @type str |
|
1006 @param hostname host name of the device |
|
1007 @type str |
|
1008 @param country WiFi country code (unused) |
|
1009 @type str |
1002 @return tuple containing a flag indicating success and an error message |
1010 @return tuple containing a flag indicating success and an error message |
1003 @rtype tuple of (bool, str) |
1011 @rtype tuple of (bool, str) |
1004 """ |
1012 """ |
1005 if not self.__deviceVolumeMounted(): |
1013 if not self.__deviceVolumeMounted(): |
1006 return False, self.tr("The device volume is not available.") |
1014 return False, self.tr("The device volume is not available.") |
1008 workspace = self.getWorkspace() |
1016 workspace = self.getWorkspace() |
1009 |
1017 |
1010 if Globals.versionToTuple(self._deviceData["release"]) >= (8, 0, 0): |
1018 if Globals.versionToTuple(self._deviceData["release"]) >= (8, 0, 0): |
1011 # CircuitPython >= 8.0.0: generate 'settings.toml' file |
1019 # CircuitPython >= 8.0.0: generate 'settings.toml' file |
1012 contents = ( |
1020 contents = ( |
1013 'CIRCUITPY_WIFI_SSID = "{0}"\nCIRCUITPY_WIFI_PASSWORD = "{1}"\n'.format( |
1021 'CIRCUITPY_WIFI_SSID = "{0}"\nCIRCUITPY_WIFI_PASSWORD = "{1}"\n' |
1014 ssid, password |
1022 'CIRCUITPY_WIFI_HOSTNAME = "{2}"\n'.format(ssid, password, hostname) |
1015 ) |
|
1016 ) |
1023 ) |
1017 filename = os.path.join(workspace, "settings.toml") |
1024 filename = os.path.join(workspace, "settings.toml") |
1018 if os.path.exists(filename): |
1025 if os.path.exists(filename): |
1019 ok = EricMessageBox.yesNo( |
1026 ok = EricMessageBox.yesNo( |
1020 None, |
1027 None, |
1036 |
1043 |
1037 else: |
1044 else: |
1038 # CircuitPython < 8.0.0: generate a secrets.py script |
1045 # CircuitPython < 8.0.0: generate a secrets.py script |
1039 # step 1: generate the secrets.py file |
1046 # step 1: generate the secrets.py file |
1040 contents = ( |
1047 contents = ( |
1041 'secrets = {{\n "ssid": "{0}",\n "password": "{1}",\n}}\n'.format( |
1048 'secrets = {{\n "ssid": "{0}",\n "password": "{1}",\n' |
1042 ssid, password |
1049 ' "hostname": "{2}",\n}}\n'.format(ssid, password, hostname) |
1043 ) |
|
1044 ) |
1050 ) |
1045 filename = os.path.join(workspace, "secrets.py") |
1051 filename = os.path.join(workspace, "secrets.py") |
1046 if os.path.exists(filename): |
1052 if os.path.exists(filename): |
1047 ok = EricMessageBox.yesNo( |
1053 ok = EricMessageBox.yesNo( |
1048 None, |
1054 None, |
1209 if err: |
1215 if err: |
1210 return False, err |
1216 return False, err |
1211 else: |
1217 else: |
1212 return out.decode("utf-8").strip() == "True", "" |
1218 return out.decode("utf-8").strip() == "True", "" |
1213 |
1219 |
1214 def startAccessPoint(self, ssid, security=None, password=None, ifconfig=None): |
1220 def startAccessPoint( |
|
1221 self, |
|
1222 ssid, |
|
1223 security=None, |
|
1224 password=None, |
|
1225 hostname=None, |
|
1226 ifconfig=None, |
|
1227 ): |
1215 """ |
1228 """ |
1216 Public method to start the access point interface. |
1229 Public method to start the access point interface. |
1217 |
1230 |
1218 @param ssid SSID of the access point |
1231 @param ssid SSID of the access point |
1219 @type str |
1232 @type str |
1220 @param security security method (defaults to None) |
1233 @param security security method (defaults to None) |
1221 @type int (optional) |
1234 @type int (optional) |
1222 @param password password (defaults to None) |
1235 @param password password (defaults to None) |
|
1236 @type str (optional) |
|
1237 @param hostname host name of the device (defaults to None) |
1223 @type str (optional) |
1238 @type str (optional) |
1224 @param ifconfig IPv4 configuration for the access point if not default |
1239 @param ifconfig IPv4 configuration for the access point if not default |
1225 (IPv4 address, netmask, gateway address, DNS server address) |
1240 (IPv4 address, netmask, gateway address, DNS server address) |
1226 @type tuple of (str, str, str, str) |
1241 @type tuple of (str, str, str, str) |
1227 @return tuple containing a flag indicating success and an error message |
1242 @return tuple containing a flag indicating success and an error message |
1240 " WiFi access point." |
1255 " WiFi access point." |
1241 ), |
1256 ), |
1242 ) |
1257 ) |
1243 |
1258 |
1244 command = """ |
1259 command = """ |
1245 def start_ap(ssid, password): |
1260 def start_ap(ssid, password, hostname): |
1246 import wifi |
1261 import wifi |
1247 |
1262 |
1248 r = wifi.radio |
1263 r = wifi.radio |
|
1264 r.enabled = True |
|
1265 if hostname: |
|
1266 r.hostname = hostname |
1249 try: |
1267 try: |
1250 r.start_ap(ssid, password, authmode={2}) |
1268 r.start_ap(ssid, password, authmode={3}) |
1251 except ValueError as exc: |
1269 except (NotImplementedError, ValueError) as exc: |
1252 print('Error:', str(exc)) |
1270 print('Error:', str(exc)) |
1253 |
1271 |
1254 start_ap({0}, {1}) |
1272 start_ap({0}, {1}, {2}) |
1255 del start_ap |
1273 del start_ap |
1256 """.format( |
1274 """.format( |
1257 repr(ssid), repr(password), authmode |
1275 repr(ssid), repr(password), repr(hostname), authmode |
1258 ) |
1276 ) |
1259 |
1277 |
1260 out, err = self.executeCommands(command, mode=self._submitMode, timeout=15000) |
1278 out, err = self.executeCommands(command, mode=self._submitMode, timeout=15000) |
1261 if err: |
1279 if err: |
1262 return False, err |
1280 return False, err |
1394 status.append((self.tr("Chip Type"), ethStatus["chip"])) |
1412 status.append((self.tr("Chip Type"), ethStatus["chip"])) |
1395 status.append((self.tr("max. Sockets"), ethStatus["max_sockets"])) |
1413 status.append((self.tr("max. Sockets"), ethStatus["max_sockets"])) |
1396 |
1414 |
1397 return status |
1415 return status |
1398 |
1416 |
1399 def connectToLan(self, config): |
1417 def connectToLan(self, config, hostname): |
1400 """ |
1418 """ |
1401 Public method to connect the connected device to the LAN. |
1419 Public method to connect the connected device to the LAN. |
1402 |
1420 |
1403 Note: The MAC address of the interface is configured with the WIZ |
1421 Note: The MAC address of the interface is configured with the WIZ |
1404 |
1422 |
1405 @param config configuration for the connection (either the string 'dhcp' |
1423 @param config configuration for the connection (either the string 'dhcp' |
1406 for a dynamic address or a tuple of four strings with the IPv4 parameters. |
1424 for a dynamic address or a tuple of four strings with the IPv4 parameters. |
1407 @type str or tuple of (str, str, str, str) |
1425 @type str or tuple of (str, str, str, str) |
|
1426 @param hostname host name of the device |
|
1427 @type str |
1408 @return tuple containing a flag indicating success and an error message |
1428 @return tuple containing a flag indicating success and an error message |
1409 @rtype tuple of (bool, str) |
1429 @rtype tuple of (bool, str) |
1410 """ |
1430 """ |
1411 command = """{0} |
1431 command = """{0} |
1412 def connect_lan(config): |
1432 def connect_lan(config, hostname): |
1413 from adafruit_wiznet5k import adafruit_wiznet5k |
1433 from adafruit_wiznet5k import adafruit_wiznet5k |
1414 |
1434 |
1415 w5x00_init() |
1435 w5x00_init() |
1416 |
1436 |
1417 nic.mac_address = adafruit_wiznet5k._DEFAULT_MAC |
1437 nic.mac_address = adafruit_wiznet5k._DEFAULT_MAC |
1418 if config == 'dhcp': |
1438 if config == 'dhcp': |
1419 nic.set_dhcp(response_timeout=14) |
1439 nic.set_dhcp(hostname=hostname) |
1420 else: |
1440 else: |
1421 nic.ifconfig = ( |
1441 nic.ifconfig = ( |
1422 nic.unpretty_ip(config[0]), |
1442 nic.unpretty_ip(config[0]), |
1423 nic.unpretty_ip(config[1]), |
1443 nic.unpretty_ip(config[1]), |
1424 nic.unpretty_ip(config[2]), |
1444 nic.unpretty_ip(config[2]), |
1425 tuple(int(a) for a in config[3].split('.')), |
1445 tuple(int(a) for a in config[3].split('.')), |
1426 ) |
1446 ) |
1427 print(nic.ifconfig[0] != b'\x00\x00\x00\x00') |
1447 print(nic.ifconfig[0] != b'\x00\x00\x00\x00') |
1428 |
1448 |
1429 connect_lan({1}) |
1449 connect_lan({1}, {2}) |
1430 del connect_lan, w5x00_init |
1450 del connect_lan, w5x00_init |
1431 """.format( |
1451 """.format( |
1432 WiznetUtilities.cpyWiznetInit(), "'dhcp'" if config == "dhcp" else config |
1452 WiznetUtilities.cpyWiznetInit(), |
|
1453 "'dhcp'" if config == "dhcp" else config, |
|
1454 repr(hostname) if hostname else "''", |
1433 ) |
1455 ) |
1434 |
1456 |
1435 with EricOverrideCursor(): |
1457 with EricOverrideCursor(): |
1436 out, err = self.executeCommands( |
1458 out, err = self.executeCommands( |
1437 command, mode=self._submitMode, timeout=15000 |
1459 command, mode=self._submitMode, timeout=15000 |
1543 # The WIZnet 5x00 interface cannot be switched off explicitly. That means, |
1565 # The WIZnet 5x00 interface cannot be switched off explicitly. That means, |
1544 # disconnect from the LAN is all we can do. |
1566 # disconnect from the LAN is all we can do. |
1545 |
1567 |
1546 return self.disconnectFromLan() |
1568 return self.disconnectFromLan() |
1547 |
1569 |
1548 def writeLanAutoConnect(self, config): |
1570 def writeLanAutoConnect(self, config, hostname): |
1549 """ |
1571 """ |
1550 Public method to generate a script and associated configuration to connect the |
1572 Public method to generate a script and associated configuration to connect the |
1551 device to the LAN during boot time. |
1573 device to the LAN during boot time. |
1552 |
1574 |
1553 @param config configuration for the connection (either the string 'dhcp' |
1575 @param config configuration for the connection (either the string 'dhcp' |
1554 for a dynamic address or a tuple of four strings with the IPv4 parameters. |
1576 for a dynamic address or a tuple of four strings with the IPv4 parameters. |
1555 @type str or tuple of (str, str, str, str) |
1577 @type str or tuple of (str, str, str, str) |
|
1578 @param hostname host name of the device |
|
1579 @type str |
1556 @return tuple containing a flag indicating success and an error message |
1580 @return tuple containing a flag indicating success and an error message |
1557 @rtype tuple of (bool, str) |
1581 @rtype tuple of (bool, str) |
1558 """ |
1582 """ |
1559 if not self.__deviceVolumeMounted(): |
1583 if not self.__deviceVolumeMounted(): |
1560 return False, self.tr("The device volume is not available.") |
1584 return False, self.tr("The device volume is not available.") |
1567 { |
1591 { |
1568 "WIZNET_IFCONFIG_0": '"dhcp"', |
1592 "WIZNET_IFCONFIG_0": '"dhcp"', |
1569 "WIZNET_IFCONFIG_1": "", |
1593 "WIZNET_IFCONFIG_1": "", |
1570 "WIZNET_IFCONFIG_2": "", |
1594 "WIZNET_IFCONFIG_2": "", |
1571 "WIZNET_IFCONFIG_3": "", |
1595 "WIZNET_IFCONFIG_3": "", |
|
1596 "WIZNET_HOSTNAME": '"{0}"'.format(hostname) if hostname else '""', |
1572 } |
1597 } |
1573 if config == "dhcp" |
1598 if config == "dhcp" |
1574 else { |
1599 else { |
1575 "WIZNET_IFCONFIG_0": '"{0}"'.format(config[0]), |
1600 "WIZNET_IFCONFIG_0": '"{0}"'.format(config[0]), |
1576 "WIZNET_IFCONFIG_1": '"{0}"'.format(config[1]), |
1601 "WIZNET_IFCONFIG_1": '"{0}"'.format(config[1]), |
1586 os.path.dirname(__file__), "MCUScripts", "picoWiznetConnectCpy8.py" |
1611 os.path.dirname(__file__), "MCUScripts", "picoWiznetConnectCpy8.py" |
1587 ) |
1612 ) |
1588 |
1613 |
1589 else: |
1614 else: |
1590 # step 1: generate the wiznet_config.py file |
1615 # step 1: generate the wiznet_config.py file |
1591 ifconfig = "ifconfig = {0}\n".format( |
1616 ifconfig = "ifconfig = {0}\nhostname={1}\n".format( |
1592 "'dhcp'" if config == "dhcp" else config |
1617 "'dhcp'" if config == "dhcp" else config, |
|
1618 repr(hostname) if hostname else "''", |
1593 ) |
1619 ) |
1594 filename = os.path.join(workspace, "wiznet_config.py") |
1620 filename = os.path.join(workspace, "wiznet_config.py") |
1595 if os.path.exists(filename): |
1621 if os.path.exists(filename): |
1596 ok = EricMessageBox.yesNo( |
1622 ok = EricMessageBox.yesNo( |
1597 None, |
1623 None, |