613 |
613 |
614 ################################################################## |
614 ################################################################## |
615 ## Methods below implement WiFi related methods |
615 ## Methods below implement WiFi related methods |
616 ################################################################## |
616 ################################################################## |
617 |
617 |
|
618 def addDeviceWifiEntries(self, menu): |
|
619 """ |
|
620 Public method to add device specific entries to the given menu. |
|
621 |
|
622 @param menu reference to the context menu |
|
623 @type QMenu |
|
624 """ |
|
625 if not self.hasCircuitPython(): |
|
626 menu.addSeparator() |
|
627 menu.addAction(self.tr("Set Country"), self.__setCountry) |
|
628 menu.addAction(self.tr("Reset Country"), self.__resetCountry) |
|
629 |
618 def hasWifi(self): |
630 def hasWifi(self): |
619 """ |
631 """ |
620 Public method to check the availability of WiFi. |
632 Public method to check the availability of WiFi. |
621 |
633 |
622 @return tuple containing a flag indicating the availability of WiFi |
634 @return tuple containing a flag indicating the availability of WiFi |
626 if self.hasCircuitPython(): |
638 if self.hasCircuitPython(): |
627 self.__createCpyDevice() |
639 self.__createCpyDevice() |
628 return self.__cpyDevice.hasWifi() |
640 return self.__cpyDevice.hasWifi() |
629 |
641 |
630 return True, "esp32" |
642 return True, "esp32" |
|
643 |
|
644 def hasWifiCountry(self): |
|
645 """ |
|
646 Public method to check, if the device has support to set the WiFi country. |
|
647 |
|
648 @return flag indicating the support of WiFi country |
|
649 @rtype bool |
|
650 """ |
|
651 return True |
631 |
652 |
632 def getWifiData(self): |
653 def getWifiData(self): |
633 """ |
654 """ |
634 Public method to get data related to the current WiFi status. |
655 Public method to get data related to the current WiFi status. |
635 |
656 |
704 ap["status"] = self.__statusTranslations[ap["status"]] |
733 ap["status"] = self.__statusTranslations[ap["status"]] |
705 except KeyError: |
734 except KeyError: |
706 ap["status"] = str(ap["status"]) |
735 ap["status"] = str(ap["status"]) |
707 return station, ap, overall |
736 return station, ap, overall |
708 |
737 |
709 def connectWifi(self, ssid, password): |
738 def connectWifi(self, ssid, password, hostname): |
710 """ |
739 """ |
711 Public method to connect a device to a WiFi network. |
740 Public method to connect a device to a WiFi network. |
712 |
741 |
713 @param ssid name (SSID) of the WiFi network |
742 @param ssid name (SSID) of the WiFi network |
714 @type str |
743 @type str |
715 @param password password needed to connect |
744 @param password password needed to connect |
716 @type str |
745 @type str |
|
746 @param hostname host name of the device |
|
747 @type str |
717 @return tuple containing the connection status and an error string |
748 @return tuple containing the connection status and an error string |
718 @rtype tuple of (bool, str) |
749 @rtype tuple of (bool, str) |
719 """ |
750 """ |
720 if self.hasCircuitPython(): |
751 if self.hasCircuitPython(): |
721 return self.__cpyDevice.connectWifi(ssid, password) |
752 return self.__cpyDevice.connectWifi(ssid, password, hostname) |
722 |
753 |
723 command = """ |
754 command = """ |
724 def connect_wifi(ssid, password): |
755 def connect_wifi(ssid, password, hostname): |
725 import network |
756 import network |
726 import ujson |
757 import ujson |
727 from time import sleep |
758 from time import sleep |
|
759 |
|
760 if hostname: |
|
761 try: |
|
762 network.hostname(hostname) |
|
763 except AttributeError: |
|
764 pass |
728 |
765 |
729 wifi = network.WLAN(network.STA_IF) |
766 wifi = network.WLAN(network.STA_IF) |
730 wifi.active(False) |
767 wifi.active(False) |
731 wifi.active(True) |
768 wifi.active(True) |
732 wifi.connect(ssid, password) |
769 wifi.connect(ssid, password) |
735 max_wait -= 1 |
772 max_wait -= 1 |
736 sleep(0.1) |
773 sleep(0.1) |
737 status = wifi.status() |
774 status = wifi.status() |
738 print(ujson.dumps({{'connected': wifi.isconnected(), 'status': status}})) |
775 print(ujson.dumps({{'connected': wifi.isconnected(), 'status': status}})) |
739 |
776 |
740 connect_wifi({0}, {1}) |
777 connect_wifi({0}, {1}, {2}) |
741 del connect_wifi |
778 del connect_wifi |
742 """.format( |
779 """.format( |
743 repr(ssid), |
780 repr(ssid), |
744 repr(password if password else ""), |
781 repr(password if password else ""), |
|
782 repr(hostname), |
745 ) |
783 ) |
746 |
784 |
747 with EricOverrideCursor(): |
785 with EricOverrideCursor(): |
748 out, err = self.executeCommands( |
786 out, err = self.executeCommands( |
749 command, mode=self._submitMode, timeout=15000 |
787 command, mode=self._submitMode, timeout=15000 |
845 if err: |
883 if err: |
846 return False |
884 return False |
847 |
885 |
848 return out.strip() == b"True" |
886 return out.strip() == b"True" |
849 |
887 |
850 def writeCredentials(self, ssid, password): |
888 def writeCredentials(self, ssid, password, hostname, country): |
851 """ |
889 """ |
852 Public method to write the given credentials to the connected device and modify |
890 Public method to write the given credentials to the connected device and modify |
853 the start script to connect automatically. |
891 the start script to connect automatically. |
854 |
892 |
855 @param ssid SSID of the network to connect to |
893 @param ssid SSID of the network to connect to |
856 @type str |
894 @type str |
857 @param password password needed to authenticate |
895 @param password password needed to authenticate |
858 @type str |
896 @type str |
|
897 @param hostname host name of the device |
|
898 @type str |
|
899 @param country WiFi country code |
|
900 @type str |
859 @return tuple containing a flag indicating success and an error message |
901 @return tuple containing a flag indicating success and an error message |
860 @rtype tuple of (bool, str) |
902 @rtype tuple of (bool, str) |
861 """ |
903 """ |
862 if self.hasCircuitPython(): |
904 if self.hasCircuitPython(): |
863 return self.__cpyDevice.writeCredentials(ssid, password) |
905 return self.__cpyDevice.writeCredentials(ssid, password, hostname) |
864 |
906 |
865 nvsCommand = """ |
907 nvsCommand = """ |
866 def save_wifi_creds(ssid, password): |
908 def save_wifi_creds(ssid, password, hostname, country): |
867 import esp32 |
909 import esp32 |
868 |
910 |
869 nvs = esp32.NVS('wifi_creds') |
911 nvs = esp32.NVS('wifi_creds') |
870 nvs.set_blob('ssid', ssid) |
912 nvs.set_blob('ssid', ssid) |
871 nvs.set_blob('password', password) |
913 nvs.set_blob('password', password) |
|
914 nvs.set_blob('hostname', hostname) |
|
915 nvs.set_blob('country', country) |
872 nvs.commit() |
916 nvs.commit() |
873 |
917 |
874 save_wifi_creds({0}, {1}) |
918 save_wifi_creds({0}, {1}, {2}, {3}) |
875 del save_wifi_creds |
919 del save_wifi_creds |
876 """.format( |
920 """.format( |
877 repr(ssid), repr(password) if password else "''" |
921 repr(ssid), |
|
922 repr(password) if password else "''", |
|
923 repr(hostname) if hostname else "''", |
|
924 repr(country.upper()) if country else "''", |
878 ) |
925 ) |
879 bootCommand = """ |
926 bootCommand = """ |
880 def modify_boot(): |
927 def modify_boot(): |
881 add = True |
928 add = True |
882 try: |
929 try: |
1073 if err: |
1120 if err: |
1074 return False, err |
1121 return False, err |
1075 else: |
1122 else: |
1076 return out.decode("utf-8").strip() == "True", "" |
1123 return out.decode("utf-8").strip() == "True", "" |
1077 |
1124 |
1078 def startAccessPoint(self, ssid, security=None, password=None, ifconfig=None): |
1125 def startAccessPoint( |
|
1126 self, |
|
1127 ssid, |
|
1128 security=None, |
|
1129 password=None, |
|
1130 hostname=None, |
|
1131 ifconfig=None, |
|
1132 ): |
1079 """ |
1133 """ |
1080 Public method to start the access point interface. |
1134 Public method to start the access point interface. |
1081 |
1135 |
1082 @param ssid SSID of the access point |
1136 @param ssid SSID of the access point |
1083 @type str |
1137 @type str |
1084 @param security security method (defaults to None) |
1138 @param security security method (defaults to None) |
1085 @type int (optional) |
1139 @type int (optional) |
1086 @param password password (defaults to None) |
1140 @param password password (defaults to None) |
1087 @type str (optional) |
1141 @type str (optional) |
|
1142 @param hostname host name of the device (defaults to None) |
|
1143 @type str (optional) |
1088 @param ifconfig IPv4 configuration for the access point if not default |
1144 @param ifconfig IPv4 configuration for the access point if not default |
1089 (IPv4 address, netmask, gateway address, DNS server address) |
1145 (IPv4 address, netmask, gateway address, DNS server address) |
1090 @type tuple of (str, str, str, str) |
1146 @type tuple of (str, str, str, str) |
1091 @return tuple containing a flag indicating success and an error message |
1147 @return tuple containing a flag indicating success and an error message |
1092 @rtype tuple of (bool, str) |
1148 @rtype tuple of (bool, str) |
1093 """ |
1149 """ |
1094 if self.hasCircuitPython(): |
1150 if self.hasCircuitPython(): |
1095 return self.__cpyDevice.startAccessPoint( |
1151 return self.__cpyDevice.startAccessPoint( |
1096 ssid, security=security, password=password, ifconfig=ifconfig |
1152 ssid, |
|
1153 security=security, |
|
1154 password=password, |
|
1155 hostname=hostname, |
|
1156 ifconfig=ifconfig, |
1097 ) |
1157 ) |
1098 |
1158 |
1099 if security is None or password is None: |
1159 if security is None or password is None: |
1100 security = 0 |
1160 security = 0 |
1101 password = "" |
1161 password = "" |
1102 if security > 4: |
1162 if security > 4: |
1103 security = 4 # security >4 cause an error thrown by the ESP32 |
1163 security = 4 # security >4 cause an error thrown by the ESP32 |
1104 |
1164 |
1105 command = """ |
1165 command = """ |
1106 def start_ap(ssid, authmode, password, ifconfig): |
1166 def start_ap(ssid, authmode, password, hostname, ifconfig): |
1107 import network |
1167 import network |
|
1168 |
|
1169 if hostname: |
|
1170 try: |
|
1171 network.hostname(hostname) |
|
1172 except AttributeError: |
|
1173 pass |
1108 |
1174 |
1109 ap = network.WLAN(network.AP_IF) |
1175 ap = network.WLAN(network.AP_IF) |
1110 ap.active(False) |
1176 ap.active(False) |
1111 if ifconfig: |
1177 if ifconfig: |
1112 ap.ifconfig(ifconfig) |
1178 ap.ifconfig(ifconfig) |
1114 try: |
1180 try: |
1115 ap.config(ssid=ssid, authmode=authmode, password=password) |
1181 ap.config(ssid=ssid, authmode=authmode, password=password) |
1116 except: |
1182 except: |
1117 ap.config(essid=ssid, authmode=authmode, password=password) |
1183 ap.config(essid=ssid, authmode=authmode, password=password) |
1118 |
1184 |
1119 start_ap({0}, {1}, {2}, {3}) |
1185 start_ap({0}, {1}, {2}, {3}, {4}) |
1120 del start_ap |
1186 del start_ap |
1121 """.format( |
1187 """.format( |
1122 repr(ssid), security, repr(password), ifconfig |
1188 repr(ssid), security, repr(password), repr(hostname), ifconfig |
1123 ) |
1189 ) |
1124 |
1190 |
1125 out, err = self.executeCommands(command, mode=self._submitMode, timeout=15000) |
1191 out, err = self.executeCommands(command, mode=self._submitMode, timeout=15000) |
1126 if err: |
1192 if err: |
1127 return False, err |
1193 return False, err |
1256 out, err = self.executeCommands(command, mode=self._submitMode) |
1322 out, err = self.executeCommands(command, mode=self._submitMode) |
1257 if err: |
1323 if err: |
1258 return False, err |
1324 return False, err |
1259 |
1325 |
1260 return out.decode("utf-8").strip() == "True", "" |
1326 return out.decode("utf-8").strip() == "True", "" |
|
1327 |
|
1328 @pyqtSlot() |
|
1329 def __setCountry(self): |
|
1330 """ |
|
1331 Private slot to configure the country of the connected ESP32 device. |
|
1332 |
|
1333 The country is the two-letter ISO 3166-1 Alpha-2 country code. |
|
1334 """ |
|
1335 from ..WifiDialogs.WifiCountryDialog import WifiCountryDialog |
|
1336 |
|
1337 dlg = WifiCountryDialog() |
|
1338 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
1339 country, remember = dlg.getCountry() |
|
1340 if remember: |
|
1341 Preferences.setMicroPython("WifiCountry", country) |
|
1342 |
|
1343 command = """ |
|
1344 try: |
|
1345 import network |
|
1346 network.country({0}) |
|
1347 except AttributeError: |
|
1348 pass |
|
1349 """.format( |
|
1350 repr(country) |
|
1351 ) |
|
1352 |
|
1353 out, err = self.executeCommands(command, mode=self._submitMode) |
|
1354 if err: |
|
1355 self.microPython.showError("country()", err) |
|
1356 |
|
1357 @pyqtSlot() |
|
1358 def __resetCountry(self): |
|
1359 """ |
|
1360 Private slot to reset the country of the connected ESP32 device. |
|
1361 |
|
1362 The country is the two-letter ISO 3166-1 Alpha-2 country code. This method |
|
1363 resets it to the default code 'XX' representing the "worldwide" region. |
|
1364 """ |
|
1365 command = """ |
|
1366 try: |
|
1367 import network |
|
1368 network.country('XX') |
|
1369 except AttributeError: |
|
1370 pass |
|
1371 """ |
|
1372 |
|
1373 out, err = self.executeCommands(command, mode=self._submitMode) |
|
1374 if err: |
|
1375 self.microPython.showError("country()", err) |
1261 |
1376 |
1262 ################################################################## |
1377 ################################################################## |
1263 ## Methods below implement Bluetooth related methods |
1378 ## Methods below implement Bluetooth related methods |
1264 ################################################################## |
1379 ################################################################## |
1265 |
1380 |