src/eric7/MicroPython/Devices/EspDevices.py

branch
eric7
changeset 9866
0cf5dda5512f
parent 9859
829c1edbf253
child 9868
467288cffee2
equal deleted inserted replaced
9865:2eb7b5516a60 9866:0cf5dda5512f
25 from eric7.SystemUtilities import PythonUtilities 25 from eric7.SystemUtilities import PythonUtilities
26 26
27 from ..MicroPythonWidget import HAS_QTCHART 27 from ..MicroPythonWidget import HAS_QTCHART
28 from . import FirmwareGithubUrls 28 from . import FirmwareGithubUrls
29 from .DeviceBase import BaseDevice 29 from .DeviceBase import BaseDevice
30 from .CircuitPythonDevices import CircuitPythonDevice
30 31
31 32
32 class EspDevice(BaseDevice): 33 class EspDevice(BaseDevice):
33 """ 34 """
34 Class implementing the device for ESP32 and ESP8266 based boards. 35 Class implementing the device for ESP32 and ESP8266 based boards.
46 @type QObject 47 @type QObject
47 """ 48 """
48 super().__init__(microPythonWidget, deviceType, parent) 49 super().__init__(microPythonWidget, deviceType, parent)
49 50
50 self.__createEsp32Submenu() 51 self.__createEsp32Submenu()
52
53 self.__cpyDevice = None
54 # needed to delegate some methods to a CircuitPython variant
51 55
52 self.__statusTranslations = { 56 self.__statusTranslations = {
53 200: self.tr("beacon timeout"), 57 200: self.tr("beacon timeout"),
54 201: self.tr("no matching access point found"), 58 201: self.tr("no matching access point found"),
55 202: self.tr("authentication failed"), 59 202: self.tr("authentication failed"),
67 4: "WPA/WPA2", 71 4: "WPA/WPA2",
68 5: "WPA2 (CCMP)", 72 5: "WPA2 (CCMP)",
69 6: "WPA3", 73 6: "WPA3",
70 7: "WPA2/WPA3", 74 7: "WPA2/WPA3",
71 } 75 }
76
77 def __createCpyDevice(self):
78 """
79 Private method to create a CircuitPython device interface.
80 """
81 if self.hasCircuitPython() and self.__cpyDevice is None:
82 self.__cpyDevice = CircuitPythonDevice(
83 self.microPython,
84 "esp32_circuitpython",
85 "esp32",
86 hasWorkspace=False,
87 parent=self.parent(),
88 )
89
90 def setConnected(self, connected):
91 """
92 Public method to set the connection state.
93
94 Note: This method can be overwritten to perform actions upon connect
95 or disconnect of the device.
96
97 @param connected connection state
98 @type bool
99 """
100 super().setConnected(connected)
101
102 if self.hasCircuitPython():
103 self._submitMode = "paste"
104 self.__createCpyDevice()
72 105
73 def setButtons(self): 106 def setButtons(self):
74 """ 107 """
75 Public method to enable the supported action buttons. 108 Public method to enable the supported action buttons.
76 """ 109 """
339 def __showFirmwareVersions(self): 372 def __showFirmwareVersions(self):
340 """ 373 """
341 Private slot to show the firmware version of the connected device and the 374 Private slot to show the firmware version of the connected device and the
342 available firmware version. 375 available firmware version.
343 """ 376 """
377 if self.hasCircuitPython():
378 return self.__cpyDevice.showCircuitPythonVersions()
379
344 if self.microPython.isConnected(): 380 if self.microPython.isConnected():
345 if self._deviceData["mpy_name"] == "micropython": 381 if self._deviceData["mpy_name"] == "micropython":
346 url = QUrl(FirmwareGithubUrls["micropython"]) 382 url = QUrl(FirmwareGithubUrls["micropython"])
347 elif self._deviceData["mpy_name"] == "circuitpython": 383 elif self._deviceData["mpy_name"] == "circuitpython":
348 url = QUrl(FirmwareGithubUrls["circuitpython"]) 384 url = QUrl(FirmwareGithubUrls["circuitpython"])
469 @pyqtSlot() 505 @pyqtSlot()
470 def __resetDevice(self): 506 def __resetDevice(self):
471 """ 507 """
472 Private slot to reset the connected device. 508 Private slot to reset the connected device.
473 """ 509 """
474 if self.microPython.isConnected(): 510 if self.microPython.isConnected() and not self.hasCircuitPython():
475 self.microPython.deviceInterface().execute( 511 self.microPython.deviceInterface().execute(
476 "import machine\nmachine.reset()\n", mode=self._submitMode 512 "import machine\nmachine.reset()\n", mode=self._submitMode
477 ) 513 )
478 else: 514 else:
479 # perform a reset via esptool using flash_id command ignoring 515 # perform a reset via esptool using flash_id command ignoring
507 Public method to get the device documentation URL. 543 Public method to get the device documentation URL.
508 544
509 @return documentation URL of the device 545 @return documentation URL of the device
510 @rtype str 546 @rtype str
511 """ 547 """
548 if self.hasCircuitPython():
549 return self.__cpyDevice.getDocumentationUrl()
550
512 return Preferences.getMicroPython("MicroPythonDocuUrl") 551 return Preferences.getMicroPython("MicroPythonDocuUrl")
513 552
514 def getFirmwareUrl(self): 553 def getFirmwareUrl(self):
515 """ 554 """
516 Public method to get the device firmware download URL. 555 Public method to get the device firmware download URL.
517 556
518 @return firmware download URL of the device 557 @return firmware download URL of the device
519 @rtype str 558 @rtype str
520 """ 559 """
560 if self.hasCircuitPython():
561 return self.__cpyDevice.getFirmwareUrl()
562
521 return Preferences.getMicroPython("MicroPythonFirmwareUrl") 563 return Preferences.getMicroPython("MicroPythonFirmwareUrl")
522 564
523 ################################################################## 565 ##################################################################
524 ## time related methods below 566 ## time related methods below
525 ################################################################## 567 ##################################################################
549 # (year, month, day, weekday, hour, minute, second, subseconds) 591 # (year, month, day, weekday, hour, minute, second, subseconds)
550 # __IGNORE_WARNING_M891__ 592 # __IGNORE_WARNING_M891__
551 # https://docs.micropython.org/en/latest/library/machine.RTC.html#machine-rtc 593 # https://docs.micropython.org/en/latest/library/machine.RTC.html#machine-rtc
552 # 594 #
553 # LoBo variant of MPy deviates. 595 # LoBo variant of MPy deviates.
596 if self.hasCircuitPython():
597 return super()._getSetTimeCode()
598
554 return """ 599 return """
555 def set_time(rtc_time): 600 def set_time(rtc_time):
556 import machine 601 import machine
557 rtc = machine.RTC() 602 rtc = machine.RTC()
558 try: 603 try:
576 621
577 @return tuple containing a flag indicating the availability of WiFi 622 @return tuple containing a flag indicating the availability of WiFi
578 and the WiFi type (esp32) 623 and the WiFi type (esp32)
579 @rtype tuple of (bool, str) 624 @rtype tuple of (bool, str)
580 """ 625 """
626 if self.hasCircuitPython():
627 self.__createCpyDevice()
628 return self.__cpyDevice.hasWifi()
629
581 return True, "esp32" 630 return True, "esp32"
582 631
583 def getWifiData(self): 632 def getWifiData(self):
584 """ 633 """
585 Public method to get data related to the current WiFi status. 634 Public method to get data related to the current WiFi status.
587 @return tuple of three dictionaries containing the WiFi status data 636 @return tuple of three dictionaries containing the WiFi status data
588 for the WiFi client, access point and overall data 637 for the WiFi client, access point and overall data
589 @rtype tuple of (dict, dict, dict) 638 @rtype tuple of (dict, dict, dict)
590 @exception OSError raised to indicate an issue with the device 639 @exception OSError raised to indicate an issue with the device
591 """ 640 """
641 if self.hasCircuitPython():
642 return self.__cpyDevice.getWifiData()
643
592 command = """ 644 command = """
593 def wifi_status(): 645 def wifi_status():
594 import ubinascii 646 import ubinascii
595 import ujson 647 import ujson
596 import network 648 import network
663 @param password password needed to connect 715 @param password password needed to connect
664 @type str 716 @type str
665 @return tuple containing the connection status and an error string 717 @return tuple containing the connection status and an error string
666 @rtype tuple of (bool, str) 718 @rtype tuple of (bool, str)
667 """ 719 """
720 if self.hasCircuitPython():
721 return self.__cpyDevice.connectWifi(ssid, password)
722
668 command = """ 723 command = """
669 def connect_wifi(ssid, password): 724 def connect_wifi(ssid, password):
670 import network 725 import network
671 import ujson 726 import ujson
672 from time import sleep 727 from time import sleep
712 Public method to disconnect a device from the WiFi network. 767 Public method to disconnect a device from the WiFi network.
713 768
714 @return tuple containing a flag indicating success and an error string 769 @return tuple containing a flag indicating success and an error string
715 @rtype tuple of (bool, str) 770 @rtype tuple of (bool, str)
716 """ 771 """
772 if self.hasCircuitPython():
773 return self.__cpyDevice.disconnectWifi()
774
717 command = """ 775 command = """
718 def disconnect_wifi(): 776 def disconnect_wifi():
719 import network 777 import network
720 from time import sleep 778 from time import sleep
721 779
745 @param password password needed to authenticate 803 @param password password needed to authenticate
746 @type str 804 @type str
747 @return tuple containing a flag indicating success and an error message 805 @return tuple containing a flag indicating success and an error message
748 @rtype tuple of (bool, str) 806 @rtype tuple of (bool, str)
749 """ 807 """
808 if self.hasCircuitPython():
809 return self.__cpyDevice.writeCredentials(ssid, password)
810
750 nvsCommand = """ 811 nvsCommand = """
751 def save_wifi_creds(ssid, password): 812 def save_wifi_creds(ssid, password):
752 import esp32 813 import esp32
753 814
754 nvs = esp32.NVS('wifi_creds') 815 nvs = esp32.NVS('wifi_creds')
807 Public method to remove the saved credentials from the connected device. 868 Public method to remove the saved credentials from the connected device.
808 869
809 @return tuple containing a flag indicating success and an error message 870 @return tuple containing a flag indicating success and an error message
810 @rtype tuple of (bool, str) 871 @rtype tuple of (bool, str)
811 """ 872 """
873 if self.hasCircuitPython():
874 return self.__cpyDevice.removeCredentials()
875
812 nvsCommand = """ 876 nvsCommand = """
813 def delete_wifi_creds(): 877 def delete_wifi_creds():
814 import esp32 878 import esp32
815 879
816 nvs = esp32.NVS('wifi_creds') 880 nvs = esp32.NVS('wifi_creds')
836 Public method to check, if the internet can be reached. 900 Public method to check, if the internet can be reached.
837 901
838 @return tuple containing a flag indicating reachability and an error string 902 @return tuple containing a flag indicating reachability and an error string
839 @rtype tuple of (bool, str) 903 @rtype tuple of (bool, str)
840 """ 904 """
905 if self.hasCircuitPython():
906 return self.__cpyDevice.checkInternet()
907
841 command = """ 908 command = """
842 def check_internet(): 909 def check_internet():
843 import network 910 import network
844 import socket 911 import socket
845 912
871 938
872 @return tuple containing the list of available networks as a tuple of 'Name', 939 @return tuple containing the list of available networks as a tuple of 'Name',
873 'MAC-Address', 'channel', 'RSSI' and 'security' and an error string 940 'MAC-Address', 'channel', 'RSSI' and 'security' and an error string
874 @rtype tuple of (list of tuple of (str, str, int, int, str), str) 941 @rtype tuple of (list of tuple of (str, str, int, int, str), str)
875 """ 942 """
943 if self.hasCircuitPython():
944 return self.__cpyDevice.scanNetworks()
945
876 command = """ 946 command = """
877 def scan_networks(): 947 def scan_networks():
878 import network 948 import network
879 949
880 wifi = network.WLAN(network.STA_IF) 950 wifi = network.WLAN(network.STA_IF)
926 if interface not in ("STA", "AP"): 996 if interface not in ("STA", "AP"):
927 raise ValueError( 997 raise ValueError(
928 "interface must be 'AP' or 'STA', got '{0}'".format(interface) 998 "interface must be 'AP' or 'STA', got '{0}'".format(interface)
929 ) 999 )
930 1000
1001 if self.hasCircuitPython():
1002 return self.__cpyDevice.deactivateInterface(interface)
1003
931 command = """ 1004 command = """
932 def deactivate(): 1005 def deactivate():
933 import network 1006 import network
934 from time import sleep 1007 from time import sleep
935 1008
964 (IPv4 address, netmask, gateway address, DNS server address) 1037 (IPv4 address, netmask, gateway address, DNS server address)
965 @type tuple of (str, str, str, str) 1038 @type tuple of (str, str, str, str)
966 @return tuple containing a flag indicating success and an error message 1039 @return tuple containing a flag indicating success and an error message
967 @rtype tuple of (bool, str) 1040 @rtype tuple of (bool, str)
968 """ 1041 """
1042 if self.hasCircuitPython():
1043 return self.__cpyDevice.startAccessPoint(
1044 ssid, security=security, password=password, ifconfig=ifconfig
1045 )
1046
969 if security is None or password is None: 1047 if security is None or password is None:
970 security = 0 1048 security = 0
971 password = "" 1049 password = ""
972 if security > 4: 1050 if security > 4:
973 security = 4 # security >4 cause an error thrown by the ESP32 1051 security = 4 # security >4 cause an error thrown by the ESP32
1005 Public method to stop the access point interface. 1083 Public method to stop the access point interface.
1006 1084
1007 @return tuple containg a flag indicating success and an error message 1085 @return tuple containg a flag indicating success and an error message
1008 @rtype tuple of (bool, str) 1086 @rtype tuple of (bool, str)
1009 """ 1087 """
1088 if self.hasCircuitPython():
1089 return self.__cpyDevice.stopAccessPoint()
1090
1010 return self.deactivateInterface("AP") 1091 return self.deactivateInterface("AP")
1011 1092
1012 def getConnectedClients(self): 1093 def getConnectedClients(self):
1013 """ 1094 """
1014 Public method to get a list of connected clients. 1095 Public method to get a list of connected clients.
1015 1096
1016 @return a tuple containing a list of tuples containing the client MAC-Address 1097 @return a tuple containing a list of tuples containing the client MAC-Address
1017 and the RSSI (if supported and available) and an error message 1098 and the RSSI (if supported and available) and an error message
1018 @rtype tuple of ([(bytes, int)], str) 1099 @rtype tuple of ([(bytes, int)], str)
1019 """ 1100 """
1101 if self.hasCircuitPython():
1102 return self.__cpyDevice.getConnectedClients()
1103
1020 command = """ 1104 command = """
1021 def get_stations(): 1105 def get_stations():
1022 import network 1106 import network
1023 1107
1024 ap = network.WLAN(network.AP_IF) 1108 ap = network.WLAN(network.AP_IF)
1048 1132
1049 @return flag indicating the availability of Bluetooth 1133 @return flag indicating the availability of Bluetooth
1050 @rtype bool 1134 @rtype bool
1051 @exception OSError raised to indicate an issue with the device 1135 @exception OSError raised to indicate an issue with the device
1052 """ 1136 """
1137 if self.hasCircuitPython():
1138 self.__createCpyDevice()
1139 return self.__cpyDevice.hasBluetooth()
1140
1053 command = """ 1141 command = """
1054 def has_bt(): 1142 def has_bt():
1055 try: 1143 try:
1056 import bluetooth 1144 import bluetooth
1057 if hasattr(bluetooth, 'BLE'): 1145 if hasattr(bluetooth, 'BLE'):
1078 @return list of tuples containing the translated status data label and 1166 @return list of tuples containing the translated status data label and
1079 the associated value 1167 the associated value
1080 @rtype list of tuples of (str, str) 1168 @rtype list of tuples of (str, str)
1081 @exception OSError raised to indicate an issue with the device 1169 @exception OSError raised to indicate an issue with the device
1082 """ 1170 """
1171 if self.hasCircuitPython():
1172 return self.__cpyDevice.getBluetoothStatus()
1173
1083 command = """ 1174 command = """
1084 def ble_status(): 1175 def ble_status():
1085 import bluetooth 1176 import bluetooth
1086 import ubinascii 1177 import ubinascii
1087 import ujson 1178 import ujson
1137 1228
1138 @return flag indicating the new state of the Bluetooth interface 1229 @return flag indicating the new state of the Bluetooth interface
1139 @rtype bool 1230 @rtype bool
1140 @exception OSError raised to indicate an issue with the device 1231 @exception OSError raised to indicate an issue with the device
1141 """ 1232 """
1233 if self.hasCircuitPython():
1234 return self.__cpyDevice.activateBluetoothInterface()
1235
1142 command = """ 1236 command = """
1143 def activate_ble(): 1237 def activate_ble():
1144 import bluetooth 1238 import bluetooth
1145 1239
1146 ble = bluetooth.BLE() 1240 ble = bluetooth.BLE()
1163 1257
1164 @return flag indicating the new state of the Bluetooth interface 1258 @return flag indicating the new state of the Bluetooth interface
1165 @rtype bool 1259 @rtype bool
1166 @exception OSError raised to indicate an issue with the device 1260 @exception OSError raised to indicate an issue with the device
1167 """ 1261 """
1262 if self.hasCircuitPython():
1263 return self.__cpyDevice.deactivateBluetoothInterface()
1264
1168 command = """ 1265 command = """
1169 def deactivate_ble(): 1266 def deactivate_ble():
1170 import bluetooth 1267 import bluetooth
1171 1268
1172 ble = bluetooth.BLE() 1269 ble = bluetooth.BLE()
1193 @return tuple containing a dictionary with the scan results and 1290 @return tuple containing a dictionary with the scan results and
1194 an error string 1291 an error string
1195 @rtype tuple of (dict, str) 1292 @rtype tuple of (dict, str)
1196 """ 1293 """
1197 from ..BluetoothDialogs.BluetoothAdvertisement import BluetoothAdvertisement 1294 from ..BluetoothDialogs.BluetoothAdvertisement import BluetoothAdvertisement
1295
1296 if self.hasCircuitPython():
1297 return self.__cpyDevice.getDeviceScan(timeout)
1198 1298
1199 command = """ 1299 command = """
1200 def ble_scan(): 1300 def ble_scan():
1201 import bluetooth 1301 import bluetooth
1202 import time 1302 import time

eric ide

mercurial