├── Example ├── LoRa_Maduino_Relay │ ├── LoRa_Maduino_receiver │ │ └── LoRa_Maduino_receiver.ino │ └── LoRa_Maduino_transmitter │ │ └── LoRa_Maduino_transmitter.ino ├── Lora gateway cantrol--arduino │ ├── ESP32_lora │ │ └── ESP32_lora.ino │ └── LoraRelay-receive │ │ └── LoraRelay-receive.ino └── Lora gateway cantrol │ ├── LoraRelay │ └── LoraRelay.ino │ └── workSpace │ ├── config_lora.py │ ├── controller.py │ ├── controller_esp.py │ ├── controller_esp_lora_oled.py │ ├── display_ssd1306_i2c.py │ ├── lora_node.py │ ├── main.py │ ├── ssd1306.py │ ├── sx127x.py │ ├── test.py │ └── webserver.py ├── Hardware ├── 4-Channel Lora Relay-10A v2.0.brd ├── 4-Channel Lora Relay-10A v2.0.pdf └── 4-Channel Lora Relay-10A v2.0.sch ├── LoraReceiver └── LoraReceiver.ino ├── LoraTransmitter └── LoraTransmitter.ino ├── README.MD └── md_pic ├── 4-Channel Lora Relay-10A_1.jpg ├── 4-Channel Lora Relay-10A_3.jpg ├── 4-Channel Lora Relay-10A_4.png ├── 4-Channel Lora Relay-10A_5.png ├── 4-Channel Lora Relay-10A_6.png ├── 4-Channel Lora Relay-10A_7.gif └── 4-Channel Lora Relay-10A_8.png /Example/LoRa_Maduino_Relay/LoRa_Maduino_receiver/LoRa_Maduino_receiver.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const int DIO0 = 2; 4 | const int DIO1 = 6; 5 | const int DIO2 = 7; 6 | const int DIO5 = 8; 7 | 8 | const int LORA_RST = 9; 9 | const int LORA_CS = 10; 10 | 11 | const int SPI_MOSI = 11; 12 | const int SPI_MISO = 12; 13 | const int SPI_SCK = 13; 14 | 15 | #define FREQUENCY 434.0 16 | #define BANDWIDTH 125.0 17 | #define SPREADING_FACTOR 9 18 | #define CODING_RATE 7 19 | #define OUTPUT_POWER 10 20 | #define PREAMBLE_LEN 8 21 | #define GAIN 0 22 | 23 | SX1278 radio = new Module(LORA_CS, DIO0, LORA_RST, DIO1); 24 | 25 | #define LED 5 26 | #define RELAY1 4 27 | #define RELAY2 3 28 | #define RELAY3 A3 29 | #define RELAY4 A2 30 | 31 | 32 | bool RS1 = LOW; 33 | bool RS2 = LOW; 34 | bool RS3 = LOW; 35 | bool RS4 = LOW; 36 | 37 | 38 | void setup() 39 | { 40 | pinMode(5, OUTPUT); 41 | pinMode(4, OUTPUT); 42 | pinMode(3, OUTPUT); 43 | pinMode(A3, OUTPUT); 44 | pinMode(A2, OUTPUT); 45 | 46 | digitalWrite(5, HIGH); 47 | digitalWrite(4, LOW); 48 | digitalWrite(3, LOW); 49 | digitalWrite(A3, LOW); 50 | digitalWrite(A2, LOW); 51 | 52 | //while (!Serial); 53 | Serial.begin(115200); 54 | delay(100); 55 | 56 | 57 | 58 | int state = radio.begin(FREQUENCY, BANDWIDTH, SPREADING_FACTOR, CODING_RATE, SX127X_SYNC_WORD, OUTPUT_POWER, PREAMBLE_LEN, GAIN); 59 | //int state = radio.begin(); 60 | if (state == ERR_NONE) 61 | { 62 | Serial.println(F("success!")); 63 | } 64 | else 65 | { 66 | Serial.print(F("failed, code ")); 67 | Serial.println(state); 68 | while (true) 69 | ; 70 | } 71 | 72 | radio.setDio0Action(setFlag); 73 | 74 | // start listening for LoRa packets 75 | Serial.print(F("[SX1278] Starting to listen ... ")); 76 | state = radio.startReceive(); 77 | if (state == ERR_NONE) { 78 | Serial.println(F("success!")); 79 | } else { 80 | Serial.print(F("failed, code ")); 81 | Serial.println(state); 82 | while (true); 83 | } 84 | } 85 | 86 | volatile bool receivedFlag = false; 87 | 88 | // disable interrupt when it's not needed 89 | volatile bool enableInterrupt = true; 90 | 91 | // this function is called when a complete packet 92 | // is received by the module 93 | // IMPORTANT: this function MUST be 'void' type 94 | // and MUST NOT have any arguments! 95 | void setFlag(void) { 96 | // check if the interrupt is enabled 97 | if(!enableInterrupt) { 98 | return; 99 | } 100 | 101 | // we got a packet, set the flag 102 | receivedFlag = true; 103 | } 104 | 105 | void loop() 106 | { 107 | 108 | if (receivedFlag) 109 | { 110 | digitalWrite(LED,LOW); 111 | enableInterrupt = false; 112 | receivedFlag = false; 113 | 114 | 115 | // you can read received data as an Arduino String 116 | String str; 117 | int state = radio.readData(str); 118 | 119 | 120 | 121 | if (state == ERR_NONE) { 122 | // packet was successfully received 123 | Serial.println(F("[SX1278] Received packet!")); 124 | Serial.println(str); 125 | if (str.indexOf("RELAY01") != -1) 126 | { 127 | RS1 = !RS1; 128 | switch (RS1) { 129 | case LOW: {digitalWrite(RELAY1,LOW); } break; 130 | case HIGH: {digitalWrite(RELAY1,HIGH);} break; 131 | } 132 | } 133 | else if (str.indexOf("RELAY02") != -1) 134 | { 135 | RS2 = !RS2; 136 | switch (RS2) { 137 | case LOW: {digitalWrite(RELAY2,LOW); } break; 138 | case HIGH: {digitalWrite(RELAY2,HIGH); } break; 139 | } 140 | } 141 | else if (str.indexOf("RELAY03") != -1) 142 | { 143 | RS3 = !RS3; 144 | switch (RS3) { 145 | case LOW: {digitalWrite(RELAY3,LOW);} break; 146 | case HIGH: {digitalWrite(RELAY3,HIGH); } break; 147 | } 148 | } 149 | else if (str.indexOf("RELAY04") != -1) 150 | { 151 | RS4 = !RS4; 152 | switch (RS4) { 153 | case LOW: {digitalWrite(RELAY4,LOW); } break; 154 | case HIGH: {digitalWrite(RELAY4,HIGH); } break; 155 | } 156 | } 157 | 158 | } 159 | digitalWrite(LED,HIGH); 160 | radio.startReceive(); 161 | enableInterrupt = true; 162 | } 163 | 164 | } 165 | 166 | 167 | -------------------------------------------------------------------------------- /Example/LoRa_Maduino_Relay/LoRa_Maduino_transmitter/LoRa_Maduino_transmitter.ino: -------------------------------------------------------------------------------- 1 | // include the library 2 | #include 3 | 4 | //328p 5 | 6 | #define DIO0 2 7 | #define DIO1 6 8 | #define DIO2 7 9 | #define DIO5 8 10 | 11 | #define LORA_RST 9 12 | #define LORA_CS 10 13 | 14 | #define SPI_MOSI 11 15 | #define SPI_MISO 12 16 | #define SPI_SCK 13 17 | 18 | #define FREQUENCY 434.0 19 | #define BANDWIDTH 125.0 20 | #define SPREADING_FACTOR 9 21 | #define CODING_RATE 7 22 | #define OUTPUT_POWER 10 23 | #define PREAMBLE_LEN 8 24 | #define GAIN 0 25 | 26 | SX1278 radio = new Module(LORA_CS, DIO0, LORA_RST, DIO1); 27 | 28 | #define R1 A0 29 | #define R2 A1 30 | #define R3 A2 31 | #define R4 A3 32 | 33 | 34 | void setup() 35 | { 36 | pinMode(R1,INPUT_PULLUP); 37 | pinMode(R2,INPUT_PULLUP); 38 | pinMode(R3,INPUT_PULLUP); 39 | pinMode(R4,INPUT_PULLUP); 40 | 41 | Serial.begin(115200); 42 | 43 | 44 | int state = radio.begin(FREQUENCY, BANDWIDTH, SPREADING_FACTOR, CODING_RATE, SX127X_SYNC_WORD, OUTPUT_POWER, PREAMBLE_LEN, GAIN); 45 | //int state = radio.begin(); 46 | if (state == ERR_NONE) 47 | { 48 | Serial.println(F("success!")); 49 | } 50 | else 51 | { 52 | Serial.print(F("failed, code ")); 53 | Serial.println(state); 54 | while (true) 55 | ; 56 | } 57 | 58 | 59 | } 60 | 61 | 62 | 63 | void loop() 64 | { 65 | int S1 = digitalRead(R1); 66 | int S2 = digitalRead(R2); 67 | int S3 = digitalRead(R3); 68 | int S4 = digitalRead(R4); 69 | int transtatus = 0; 70 | String str = ""; 71 | if (S1 == 0) 72 | { 73 | str = "RELAY01"; 74 | transtatus = 1; 75 | } 76 | else if (S2 == 0) 77 | { 78 | str = "RELAY02"; 79 | transtatus = 1; 80 | } 81 | else if (S3 == 0) 82 | { 83 | str = "RELAY03"; 84 | transtatus = 1; 85 | } 86 | else if (S4 == 0) 87 | { 88 | str = "RELAY04"; 89 | transtatus = 1; 90 | } 91 | 92 | if (transtatus) 93 | { 94 | Serial.println(str); 95 | int state = radio.transmit(str); 96 | 97 | if (state == ERR_NONE) 98 | { 99 | // the packet was successfully transmitted 100 | Serial.println(F(" success!")); 101 | // print measured data rate 102 | Serial.print(F("[SX1278] Datarate:\t")); 103 | Serial.print(radio.getDataRate()); 104 | Serial.println(F(" bps")); 105 | } 106 | else if (state == ERR_PACKET_TOO_LONG) 107 | { 108 | // the supplied packet was longer than 256 bytes 109 | Serial.println(F("too long!")); 110 | } 111 | else if (state == ERR_TX_TIMEOUT) 112 | { 113 | // timeout occurred while transmitting packet 114 | Serial.println(F("timeout!")); 115 | } 116 | else 117 | { 118 | // some other error occurred 119 | Serial.print(F("failed, code ")); 120 | Serial.println(state); 121 | } 122 | 123 | // wait for a second before transmitting again 124 | transtatus = 0; 125 | delay(200); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol--arduino/ESP32_lora/ESP32_lora.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //SSD1306 10 | #define SCREEN_WIDTH 128 // OLED display width, in pixels 11 | #define SCREEN_HEIGHT 64 // OLED display height, in pixels 12 | 13 | // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) 14 | #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) 15 | Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); 16 | 17 | #define LOGO_HEIGHT 16 18 | #define LOGO_WIDTH 16 19 | 20 | 21 | //esp32 22 | #define DIO0 35 23 | #define DIO1 39 24 | 25 | #define LORA_RST 2 26 | #define LORA_CS 25 27 | 28 | #define SPI_MOSI 13 29 | #define SPI_MISO 12 30 | #define SPI_SCK 14 31 | 32 | #define FREQUENCY 434.0 33 | #define BANDWIDTH 125.0 34 | #define SPREADING_FACTOR 9 35 | #define CODING_RATE 7 36 | #define OUTPUT_POWER 10 37 | #define PREAMBLE_LEN 8 38 | #define GAIN 0 39 | 40 | SX1278 radio = new Module(LORA_CS, DIO0, LORA_RST, DIO1, SPI, SPISettings()); 41 | 42 | const char *ssid = "Makerfabs"; 43 | const char *password = "20160704"; 44 | 45 | WebServer server(80); 46 | String form = 47 | " \ 48 | \ 49 | \ 50 | LED Button\ 51 | \ 63 | \ 64 | \ 65 | \ 66 |

Lora Relay

\ 67 | \ 114 |
\ 115 |
\ 116 |
\ 117 |
\ 118 |
\ 119 |
\ 120 |
\ 121 |
\ 122 |
\ 123 |
\ 124 |
\ 125 | \ 126 | "; 127 | 128 | void handleRoot(){ 129 | Serial.println("Access"); 130 | server.send(200, "text/html", form); 131 | } 132 | 133 | 134 | void handleP1() 135 | { 136 | Serial.println("1"); 137 | radio.transmit("R1ON!"); 138 | Serial.print(radio.getDataRate()); 139 | Serial.println(F(" bps")); 140 | } 141 | void handleP2() 142 | { 143 | Serial.println("2"); 144 | radio.transmit("R1OFF!"); 145 | Serial.print(radio.getDataRate()); 146 | Serial.println(F(" bps")); 147 | } 148 | void handleP3() 149 | { 150 | Serial.println("3"); 151 | radio.transmit("R2ON!"); 152 | Serial.print(radio.getDataRate()); 153 | Serial.println(F(" bps")); 154 | } 155 | void handleP4() 156 | { 157 | Serial.println("4"); 158 | radio.transmit("R2OFF!"); 159 | Serial.print(radio.getDataRate()); 160 | Serial.println(F(" bps")); 161 | } 162 | void handleP5() 163 | { 164 | Serial.println("5"); 165 | radio.transmit("R3ON!"); 166 | Serial.print(radio.getDataRate()); 167 | Serial.println(F(" bps")); 168 | } 169 | void handleP6() 170 | { 171 | Serial.println("6"); 172 | radio.transmit("R3OFF!"); 173 | Serial.print(radio.getDataRate()); 174 | Serial.println(F(" bps")); 175 | } 176 | void handleP7() 177 | { 178 | Serial.println("7"); 179 | radio.transmit("R4ON!"); 180 | Serial.print(radio.getDataRate()); 181 | Serial.println(F(" bps")); 182 | } 183 | void handleP8() 184 | { 185 | Serial.println("8"); 186 | radio.transmit("R4OFF!"); 187 | Serial.print(radio.getDataRate()); 188 | Serial.println(F(" bps")); 189 | } 190 | 191 | void setup() 192 | { 193 | Serial.begin(115200); 194 | Serial.println(); 195 | 196 | SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI); 197 | //SPI.begin(); 198 | if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64 199 | Serial.println(F("SSD1306 allocation failed")); 200 | for(;;); // Don't proceed, loop forever 201 | } 202 | 203 | // Show initial display buffer contents on the screen -- 204 | // the library initializes this with an Adafruit splash screen. 205 | display.display(); 206 | delay(200); // Pause for 2 seconds 207 | 208 | // Clear the buffer 209 | display.clearDisplay(); 210 | 211 | int state = radio.begin(FREQUENCY, BANDWIDTH, SPREADING_FACTOR, CODING_RATE, SX127X_SYNC_WORD, OUTPUT_POWER, PREAMBLE_LEN, GAIN); 212 | //int state = radio.begin(); 213 | if (state == ERR_NONE) 214 | { 215 | Serial.println(F("success!")); 216 | } 217 | else 218 | { 219 | Serial.print(F("failed, code ")); 220 | Serial.println(state); 221 | while (true) 222 | ; 223 | } 224 | 225 | WiFi.mode(WIFI_STA); 226 | WiFi.setSleep(false); 227 | WiFi.begin(ssid, password); 228 | while (WiFi.status() != WL_CONNECTED) 229 | { 230 | delay(500); 231 | Serial.print("."); 232 | } 233 | Serial.println("Connected"); 234 | Serial.print("IP Address:"); 235 | Serial.println(WiFi.localIP()); 236 | 237 | display.setTextSize(1); // Normal 1:1 pixel scale 238 | display.setTextColor(SSD1306_WHITE); // Draw white text 239 | display.setCursor(0,0); // Start at top-left corner 240 | display.print(WiFi.localIP()); 241 | display.display(); 242 | 243 | server.on("/", handleRoot); 244 | server.on("/1/", handleP1); 245 | server.on("/2/", handleP2); 246 | server.on("/3/", handleP3); 247 | server.on("/4/", handleP4); 248 | server.on("/5/", handleP5); 249 | server.on("/6/", handleP6); 250 | server.on("/7/", handleP7); 251 | server.on("/8/", handleP8); 252 | 253 | 254 | server.begin(); 255 | Serial.println("Web server started"); 256 | 257 | } 258 | 259 | void loop() 260 | { 261 | server.handleClient(); 262 | 263 | } 264 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol--arduino/LoraRelay-receive/LoraRelay-receive.ino: -------------------------------------------------------------------------------- 1 | // Arduino9x_RX 2 | // -*- mode: C++ -*- 3 | // Example sketch showing how to create a simple messaging client (receiver) 4 | // with the RH_RF95 class. RH_RF95 class does not provide for addressing or 5 | // reliability, so you should only use RH_RF95 if you do not need the higher 6 | // level messaging abilities. 7 | // It is designed to work with the other example Arduino9x_TX 8 | 9 | #include 10 | 11 | const int DIO0 = 2; 12 | const int DIO1 = 6; 13 | const int DIO2 = 7; 14 | const int DIO5 = 8; 15 | 16 | const int LORA_RST = 9; 17 | const int LORA_CS = 10; 18 | 19 | const int SPI_MOSI = 11; 20 | const int SPI_MISO = 12; 21 | const int SPI_SCK = 13; 22 | 23 | #define FREQUENCY 434.0 24 | #define BANDWIDTH 125.0 25 | #define SPREADING_FACTOR 9 26 | #define CODING_RATE 7 27 | #define OUTPUT_POWER 10 28 | #define PREAMBLE_LEN 8 29 | #define GAIN 0 30 | 31 | SX1278 radio = new Module(LORA_CS, DIO0, LORA_RST, DIO1); 32 | 33 | #define LED 5 34 | 35 | 36 | 37 | String RS1="0"; 38 | String RS2="0"; 39 | String RS3="0"; 40 | String RS4="0"; 41 | 42 | 43 | void setup() 44 | { 45 | pinMode(5, OUTPUT); 46 | pinMode(4, OUTPUT); 47 | pinMode(3, OUTPUT); 48 | pinMode(A3, OUTPUT); 49 | pinMode(A2, OUTPUT); 50 | 51 | digitalWrite(5, HIGH); 52 | digitalWrite(4, LOW); 53 | digitalWrite(3, LOW); 54 | digitalWrite(A3, LOW); 55 | digitalWrite(A2, LOW); 56 | 57 | //while (!Serial); 58 | Serial.begin(115200); 59 | delay(100); 60 | 61 | 62 | 63 | int state = radio.begin(FREQUENCY, BANDWIDTH, SPREADING_FACTOR, CODING_RATE, SX127X_SYNC_WORD, OUTPUT_POWER, PREAMBLE_LEN, GAIN); 64 | //int state = radio.begin(); 65 | if (state == ERR_NONE) 66 | { 67 | Serial.println(F("success!")); 68 | } 69 | else 70 | { 71 | Serial.print(F("failed, code ")); 72 | Serial.println(state); 73 | while (true) 74 | ; 75 | } 76 | 77 | radio.setDio0Action(setFlag); 78 | 79 | // start listening for LoRa packets 80 | Serial.print(F("[SX1278] Starting to listen ... ")); 81 | state = radio.startReceive(); 82 | if (state == ERR_NONE) { 83 | Serial.println(F("success!")); 84 | } else { 85 | Serial.print(F("failed, code ")); 86 | Serial.println(state); 87 | while (true); 88 | } 89 | } 90 | 91 | volatile bool receivedFlag = false; 92 | 93 | // disable interrupt when it's not needed 94 | volatile bool enableInterrupt = true; 95 | 96 | // this function is called when a complete packet 97 | // is received by the module 98 | // IMPORTANT: this function MUST be 'void' type 99 | // and MUST NOT have any arguments! 100 | void setFlag(void) { 101 | // check if the interrupt is enabled 102 | if(!enableInterrupt) { 103 | return; 104 | } 105 | 106 | // we got a packet, set the flag 107 | receivedFlag = true; 108 | } 109 | 110 | void loop() 111 | { 112 | if (receivedFlag) 113 | { 114 | digitalWrite(LED, LOW); 115 | enableInterrupt = false; 116 | 117 | // reset flag 118 | receivedFlag = false; 119 | 120 | // you can read received data as an Arduino String 121 | String str; 122 | int state = radio.readData(str); 123 | 124 | // you can also read received data as byte array 125 | /* 126 | byte byteArr[8]; 127 | int state = radio.readData(byteArr, 8); 128 | */ 129 | 130 | if (state == ERR_NONE) { 131 | // packet was successfully received 132 | Serial.println(F("[SX1278] Received packet!")); 133 | if (str.indexOf("R1ON") != -1) 134 | { 135 | digitalWrite(4, HIGH); //RELAY 1 136 | RS1 = "1"; 137 | 138 | } 139 | 140 | else if (str.indexOf("R1OFF") != -1) 141 | { 142 | digitalWrite(4, LOW); 143 | RS1 = "0"; 144 | 145 | } 146 | else if (str.indexOf("R2ON") != -1) 147 | { 148 | digitalWrite(3, HIGH); //RELAY 2 149 | RS2 = "1"; 150 | 151 | } 152 | 153 | else if (str.indexOf("R2OFF") != -1) 154 | { 155 | digitalWrite(3, LOW); 156 | RS2 = "0"; 157 | 158 | } 159 | else if (str.indexOf("R3ON") != -1) 160 | { 161 | digitalWrite(A3, HIGH); //RELAY 3 162 | RS3 = "1"; 163 | 164 | } 165 | 166 | else if (str.indexOf("R3OFF") != -1) 167 | { 168 | digitalWrite(A3, LOW); 169 | RS3 = "0"; 170 | } 171 | else if (str.indexOf("R4ON") != -1) 172 | { 173 | digitalWrite(A2, HIGH); //RELAY 4 174 | RS4 = "1"; 175 | } 176 | 177 | else if (str.indexOf("R4OFF") != -1) 178 | { 179 | digitalWrite(A2, LOW); 180 | RS4 = "0"; 181 | } 182 | 183 | Serial.println(str); 184 | String message; 185 | message = RS1+RS2+RS3+RS4; 186 | Serial.println(message); 187 | } 188 | digitalWrite(LED, HIGH); 189 | radio.startReceive(); 190 | 191 | // we're ready to receive more packets, 192 | // enable interrupt service routine 193 | enableInterrupt = true; 194 | } 195 | 196 | } 197 | 198 | 199 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/LoraRelay/LoraRelay.ino: -------------------------------------------------------------------------------- 1 | // Arduino9x_RX 2 | // -*- mode: C++ -*- 3 | // Example sketch showing how to create a simple messaging client (receiver) 4 | // with the RH_RF95 class. RH_RF95 class does not provide for addressing or 5 | // reliability, so you should only use RH_RF95 if you do not need the higher 6 | // level messaging abilities. 7 | // It is designed to work with the other example Arduino9x_TX 8 | 9 | #include 10 | #include 11 | 12 | #define RFM95_CS 10 13 | #define RFM95_RST 9 14 | #define RFM95_INT 2 15 | 16 | // Change to 868.0 or other frequency, must match RX's freq! 17 | #define RF95_FREQ 433.0 18 | 19 | // Singleton instance of the radio driver 20 | RH_RF95 rf95(RFM95_CS, RFM95_INT); 21 | 22 | // Blinky on receipt 23 | #define LED 5 24 | 25 | 26 | int count=0; 27 | String RS1="0"; 28 | String RS2="0"; 29 | String RS3="0"; 30 | String RS4="0"; 31 | 32 | 33 | void setup() 34 | { 35 | pinMode(5, OUTPUT); 36 | pinMode(4, OUTPUT); 37 | pinMode(3, OUTPUT); 38 | pinMode(A3, OUTPUT); 39 | pinMode(A2, OUTPUT); 40 | 41 | digitalWrite(5, HIGH); 42 | digitalWrite(4, LOW); 43 | digitalWrite(3, LOW); 44 | digitalWrite(A3, LOW); 45 | digitalWrite(A2, LOW); 46 | 47 | pinMode(RFM95_RST, OUTPUT); 48 | digitalWrite(RFM95_RST, HIGH); 49 | 50 | //while (!Serial); 51 | Serial.begin(115200); 52 | delay(100); 53 | 54 | Serial.println("Arduino LoRa RX Test!"); 55 | 56 | // manual reset 57 | digitalWrite(RFM95_RST, LOW); 58 | delay(10); 59 | digitalWrite(RFM95_RST, HIGH); 60 | delay(10); 61 | 62 | while (!rf95.init()) { 63 | Serial.println("LoRa radio init failed"); 64 | while (1); 65 | } 66 | Serial.println("LoRa radio init OK!"); 67 | 68 | // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM 69 | if (!rf95.setFrequency(RF95_FREQ)) { 70 | Serial.println("setFrequency failed"); 71 | while (1); 72 | } 73 | Serial.print("Set Freq to: "); Serial.println(RF95_FREQ); 74 | 75 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 76 | 77 | // The default transmitter power is 13dBm, using PA_BOOST. 78 | // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 79 | // you can set transmitter powers from 5 to 23 dBm: 80 | rf95.setTxPower(23, false); 81 | } 82 | 83 | void loop() 84 | { 85 | //digitalWrite(LED, LOW); 86 | if (rf95.available()) 87 | { 88 | 89 | // Should be a message for us now 90 | uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; 91 | uint8_t len = sizeof(buf); 92 | 93 | if (rf95.recv(buf, &len)) 94 | { 95 | 96 | digitalWrite(LED, LOW); 97 | RH_RF95::printBuffer("Received: ", buf, len); 98 | String msg = String((char *)buf); 99 | Serial.println(msg); 100 | Serial.print("RSSI: "); 101 | Serial.println(rf95.lastRssi(), DEC); 102 | 103 | Serial.println(); 104 | if (msg.indexOf("RELAY") == 0) 105 | { 106 | String message ; 107 | if (msg.indexOf("R1ON") != -1) 108 | { 109 | digitalWrite(4, HIGH); //RELAY 1 110 | RS1 = "1"; 111 | 112 | } 113 | 114 | else if (msg.indexOf("R1OFF") != -1) 115 | { 116 | digitalWrite(4, LOW); 117 | RS1 = "0"; 118 | 119 | } 120 | else if (msg.indexOf("R2ON") != -1) 121 | { 122 | digitalWrite(3, HIGH); //RELAY 2 123 | RS2 = "1"; 124 | 125 | } 126 | 127 | else if (msg.indexOf("R2OFF") != -1) 128 | { 129 | digitalWrite(3, LOW); 130 | RS2 = "0"; 131 | 132 | } 133 | else if (msg.indexOf("R3ON") != -1) 134 | { 135 | digitalWrite(A3, HIGH); //RELAY 3 136 | RS3 = "1"; 137 | 138 | } 139 | 140 | else if (msg.indexOf("R3OFF") != -1) 141 | { 142 | digitalWrite(A3, LOW); 143 | RS3 = "0"; 144 | } 145 | else if (msg.indexOf("R4ON") != -1) 146 | { 147 | digitalWrite(A2, HIGH); //RELAY 4 148 | RS4 = "1"; 149 | } 150 | 151 | else if (msg.indexOf("R4OFF") != -1) 152 | { 153 | digitalWrite(A2, LOW); 154 | RS4 = "0"; 155 | } 156 | 157 | Serial.println(message); 158 | 159 | message = RS1+RS2+RS3+RS4; 160 | Serial.println(message); 161 | uint8_t radioPacket[message.length() + 1]; 162 | message.toCharArray(radioPacket, message.length() + 1); 163 | radioPacket[message.length() + 1] = '\0'; 164 | Serial.println("Sending..."); 165 | delay(10); 166 | rf95.send((uint8_t *)radioPacket, message.length() + 1); 167 | 168 | /*uint8_t data[] = {R1S,R2S,R3S,R4S}; 169 | for (int i = 0; i < 4; i++) Serial.print(data[i]); 170 | rf95.send(data, sizeof(data)); 171 | rf95.waitPacketSent();*/ 172 | digitalWrite(LED, HIGH); 173 | } 174 | delay(1000); 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/workSpace/config_lora.py: -------------------------------------------------------------------------------- 1 | #判断运行环境,mcu,是否有屏幕,加载相应配置。 2 | 3 | 4 | 5 | import sys 6 | import os 7 | import time 8 | 9 | """ 10 | >>>sys.implementation.name 11 | 'micropython' 12 | >>> os.uname() 13 | (sysname='esp32', nodename='esp32', release='1.9.1', version='v1.9.1-224-g83d3f3f-dirty on 2017-12-12', machine='ESP32 module with ESP32') 14 | """ 15 | 16 | #判断系统和单片机型号 17 | IS_PC = False 18 | IS_MICROPYTHON = (sys.implementation.name == 'micropython') 19 | IS_ESP8266 = (os.uname().sysname == 'esp8266') 20 | IS_ESP32 = (os.uname().sysname == 'esp32') 21 | IS_LORA_OLED = None 22 | IS_RPi = not (IS_MICROPYTHON or IS_PC) 23 | 24 | 25 | def mac2eui(mac): 26 | mac = mac[0:6] + 'fffe' + mac[6:] 27 | return hex(int(mac[0:2], 16) ^ 2)[2:] + mac[2:] 28 | 29 | #本测试为ESP32 30 | if IS_MICROPYTHON: 31 | 32 | # Node Name 33 | import machine 34 | import ubinascii 35 | 36 | """ 37 | >>> machine.unique_id() 38 | b'$o(\xa6C\x90' 39 | >>> str(machine.unique_id(),"utf-8") 40 | '$o(C' 41 | >>> machine.unique_id().decode() 42 | '$o(C' 43 | >>> ubinascii.hexlify(machine.unique_id()) 44 | b'246f28a64390' 45 | """ 46 | 47 | #获取芯片的uuid 48 | uuid = ubinascii.hexlify(machine.unique_id()).decode() 49 | 50 | if IS_ESP8266: 51 | NODE_NAME = 'ESP8266_' 52 | if IS_ESP32: 53 | NODE_NAME = 'ESP32_' 54 | import esp 55 | IS_LORA_OLED = True#(esp.flash_size() > 5000000) 56 | 57 | NODE_EUI = mac2eui(uuid) 58 | NODE_NAME = NODE_NAME + uuid 59 | 60 | print("NODE_NAME is :" , NODE_NAME) 61 | 62 | # millisecond 63 | millisecond = time.ticks_ms 64 | 65 | # Controller 66 | #判断是否为模拟SPI 67 | SOFT_SPI = None 68 | #判断是否是自带屏幕的版本 69 | if IS_LORA_OLED: 70 | #指向调用的Controller对象 71 | from controller_esp_lora_oled import Controller 72 | SOFT_SPI = False#True 73 | else: 74 | from controller_esp import Controller 75 | 76 | 77 | 78 | if IS_RPi: 79 | 80 | # Node Name 81 | import socket 82 | NODE_NAME = 'RPi_' + socket.gethostname() 83 | 84 | # millisecond 85 | millisecond = lambda : time.time() * 1000 86 | 87 | # Controller 88 | from controller_rpi import Controller 89 | 90 | 91 | 92 | if IS_PC: 93 | 94 | # Node Name 95 | import socket 96 | NODE_NAME = 'PC_' + socket.gethostname() 97 | 98 | # millisecond 99 | millisecond = lambda : time.time() * 1000 100 | 101 | # Controller 102 | from controller_pc import Controller 103 | 104 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/workSpace/controller.py: -------------------------------------------------------------------------------- 1 | 2 | from time import sleep 3 | 4 | 5 | class Controller: 6 | 7 | class Mock: 8 | pass 9 | 10 | ON_BOARD_LED_PIN_NO = None 11 | ON_BOARD_LED_HIGH_IS_ON = True 12 | GPIO_PINS = [] 13 | 14 | PIN_ID_FOR_LORA_RESET = None 15 | 16 | PIN_ID_FOR_LORA_SS = None 17 | PIN_ID_SCK = None 18 | PIN_ID_MOSI = None 19 | PIN_ID_MISO = None 20 | 21 | PIN_ID_FOR_LORA_DIO0 = None 22 | PIN_ID_FOR_LORA_DIO1 = None 23 | PIN_ID_FOR_LORA_DIO2 = None 24 | PIN_ID_FOR_LORA_DIO3 = None 25 | PIN_ID_FOR_LORA_DIO4 = None 26 | PIN_ID_FOR_LORA_DIO5 = None 27 | 28 | 29 | def __init__(self, 30 | pin_id_led = ON_BOARD_LED_PIN_NO, 31 | on_board_led_high_is_on = ON_BOARD_LED_HIGH_IS_ON, 32 | pin_id_reset = PIN_ID_FOR_LORA_RESET, 33 | blink_on_start = (2, 0.5, 0.5)): 34 | 35 | self.pin_led = self.prepare_pin(pin_id_led) 36 | self.on_board_led_high_is_on = on_board_led_high_is_on 37 | self.pin_reset = self.prepare_pin(pin_id_reset) 38 | self.reset_pin(self.pin_reset) 39 | self.spi = self.prepare_spi(self.get_spi()) 40 | self.transceivers = {} 41 | self.blink_led(*blink_on_start) 42 | 43 | 44 | def add_transceiver(self, 45 | transceiver, 46 | pin_id_ss = PIN_ID_FOR_LORA_SS, 47 | pin_id_RxDone = PIN_ID_FOR_LORA_DIO0, 48 | pin_id_RxTimeout = PIN_ID_FOR_LORA_DIO1, 49 | pin_id_ValidHeader = PIN_ID_FOR_LORA_DIO2, 50 | pin_id_CadDone = PIN_ID_FOR_LORA_DIO3, 51 | pin_id_CadDetected = PIN_ID_FOR_LORA_DIO4, 52 | pin_id_PayloadCrcError = PIN_ID_FOR_LORA_DIO5): 53 | 54 | transceiver.transfer = self.spi.transfer 55 | transceiver.blink_led = self.blink_led 56 | 57 | transceiver.pin_ss = self.prepare_pin(pin_id_ss) 58 | transceiver.pin_RxDone = self.prepare_irq_pin(pin_id_RxDone) 59 | transceiver.pin_RxTimeout = self.prepare_irq_pin(pin_id_RxTimeout) 60 | transceiver.pin_ValidHeader = self.prepare_irq_pin(pin_id_ValidHeader) 61 | transceiver.pin_CadDone = self.prepare_irq_pin(pin_id_CadDone) 62 | transceiver.pin_CadDetected = self.prepare_irq_pin(pin_id_CadDetected) 63 | transceiver.pin_PayloadCrcError = self.prepare_irq_pin(pin_id_PayloadCrcError) 64 | 65 | transceiver.init() 66 | self.transceivers[transceiver.name] = transceiver 67 | return transceiver 68 | 69 | 70 | def prepare_pin(self, pin_id, in_out = None): 71 | reason = ''' 72 | # a pin should provide: 73 | # .pin_id 74 | # .low() 75 | # .high() 76 | # .value() # read input. 77 | # .irq() # (ESP8266/ESP32 only) ref to the irq function of real pin object. 78 | ''' 79 | raise NotImplementedError(reason) 80 | 81 | 82 | def prepare_irq_pin(self, pin_id): 83 | reason = ''' 84 | # a irq_pin should provide: 85 | # .set_handler_for_irq_on_rising_edge() # to set trigger and handler. 86 | # .detach_irq() 87 | ''' 88 | raise NotImplementedError(reason) 89 | 90 | 91 | def get_spi(self): 92 | reason = ''' 93 | # initialize SPI interface 94 | ''' 95 | raise NotImplementedError(reason) 96 | 97 | 98 | def prepare_spi(self, spi): 99 | reason = ''' 100 | # a spi should provide: 101 | # .close() 102 | # .transfer(pin_ss, address, value = 0x00) 103 | ''' 104 | raise NotImplementedError(reason) 105 | 106 | 107 | def led_on(self, on = True): 108 | self.pin_led.high() if self.on_board_led_high_is_on == on else self.pin_led.low() 109 | 110 | 111 | def blink_led(self, times = 1, on_seconds = 0.1, off_seconds = 0.1): 112 | for i in range(times): 113 | self.led_on(True) 114 | sleep(on_seconds) 115 | self.led_on(False) 116 | sleep(off_seconds) 117 | 118 | 119 | def reset_pin(self, pin, duration_low = 0.05, duration_high = 0.05): 120 | pin.low() 121 | sleep(duration_low) 122 | pin.high() 123 | sleep(duration_high) 124 | 125 | 126 | def __exit__(self): 127 | self.spi.close() 128 | 129 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/workSpace/controller_esp.py: -------------------------------------------------------------------------------- 1 | 2 | #MakePython ESP32 对象文件 3 | from machine import Pin, SPI, reset 4 | import config_lora 5 | import controller 6 | 7 | 8 | class Controller(controller.Controller): 9 | 10 | # LoRa config 11 | PIN_ID_FOR_LORA_RESET = 33 12 | 13 | PIN_ID_FOR_LORA_SS = 32 14 | PIN_ID_SCK = 14 15 | PIN_ID_MOSI = 13 16 | PIN_ID_MISO = 12 17 | 18 | PIN_ID_FOR_LORA_DIO0 = 36 19 | PIN_ID_FOR_LORA_DIO1 = None 20 | PIN_ID_FOR_LORA_DIO2 = None 21 | PIN_ID_FOR_LORA_DIO3 = None 22 | PIN_ID_FOR_LORA_DIO4 = None 23 | PIN_ID_FOR_LORA_DIO5 = None 24 | 25 | 26 | # ESP config 27 | if config_lora.IS_ESP8266: 28 | ON_BOARD_LED_PIN_NO = 2 29 | ON_BOARD_LED_HIGH_IS_ON = False 30 | GPIO_PINS = (0, 1, 2, 3, 4, 5, 12, 13, 14, 15, 16) 31 | 32 | if config_lora.IS_ESP32: 33 | ON_BOARD_LED_PIN_NO = 2 34 | ON_BOARD_LED_HIGH_IS_ON = True 35 | GPIO_PINS = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36 | 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 37 | 23, 25, 26, 27, 32, 34, 35, 36, 37, 38, 39) 38 | 39 | #构造函数 40 | def __init__(self, 41 | pin_id_led = ON_BOARD_LED_PIN_NO, 42 | on_board_led_high_is_on = ON_BOARD_LED_HIGH_IS_ON, 43 | pin_id_reset = PIN_ID_FOR_LORA_RESET, 44 | blink_on_start = (2, 0.5, 0.5)): 45 | 46 | #调用父类构造函数即controller 47 | super().__init__(pin_id_led, 48 | on_board_led_high_is_on, 49 | pin_id_reset, 50 | blink_on_start) 51 | 52 | 53 | def prepare_pin(self, pin_id, in_out = Pin.OUT): 54 | if pin_id is not None: 55 | pin = Pin(pin_id, in_out) 56 | new_pin = Controller.Mock() 57 | new_pin.pin_id = pin_id 58 | new_pin.value = pin.value 59 | 60 | if in_out == Pin.OUT: 61 | new_pin.low = lambda : pin.value(0) 62 | new_pin.high = lambda : pin.value(1) 63 | else: 64 | new_pin.irq = pin.irq 65 | 66 | return new_pin 67 | 68 | 69 | def prepare_irq_pin(self, pin_id): 70 | pin = self.prepare_pin(pin_id, Pin.IN) 71 | if pin: 72 | pin.set_handler_for_irq_on_rising_edge = lambda handler: pin.irq(handler = handler, trigger = Pin.IRQ_RISING) 73 | pin.detach_irq = lambda : pin.irq(handler = None, trigger = 0) 74 | return pin 75 | 76 | 77 | def get_spi(self): 78 | spi = None 79 | id = 1 80 | 81 | if config_lora.IS_ESP8266: 82 | spi = SPI(id, baudrate = 10000000, polarity = 0, phase = 0) 83 | spi.init() 84 | 85 | if config_lora.IS_ESP32: 86 | try: 87 | if config_lora.SOFT_SPI: id = -1#soft spi 88 | else: id = 1#hardware spi 89 | spi = SPI(id, baudrate = 10000000, polarity = 0, phase = 0, bits = 8, firstbit = SPI.MSB, 90 | sck = Pin(self.PIN_ID_SCK, Pin.OUT, Pin.PULL_DOWN), 91 | mosi = Pin(self.PIN_ID_MOSI, Pin.OUT, Pin.PULL_UP), 92 | miso = Pin(self.PIN_ID_MISO, Pin.IN, Pin.PULL_UP)) 93 | spi.init() 94 | 95 | except Exception as e: 96 | print(e) 97 | if spi: 98 | spi.deinit() 99 | spi = None 100 | reset() # in case SPI is already in use, need to reset. 101 | 102 | return spi 103 | 104 | 105 | def prepare_spi(self, spi): 106 | if spi: 107 | new_spi = Controller.Mock() 108 | 109 | def transfer(pin_ss, address, value = 0x00): 110 | response = bytearray(1) 111 | 112 | pin_ss.low() 113 | 114 | spi.write(bytes([address])) 115 | spi.write_readinto(bytes([value]), response) 116 | 117 | pin_ss.high() 118 | 119 | return response 120 | 121 | new_spi.transfer = transfer 122 | new_spi.close = spi.deinit 123 | return new_spi 124 | 125 | 126 | def __exit__(self): 127 | self.spi.close() 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/workSpace/controller_esp_lora_oled.py: -------------------------------------------------------------------------------- 1 | 2 | #MakePython ESP32 对象文件 有OLED版本 3 | #包含esp32,Lora模块,SSD1306的引脚定义 4 | import controller_esp 5 | import display_ssd1306_i2c 6 | 7 | 8 | class Controller(controller_esp.Controller, display_ssd1306_i2c.Display): 9 | 10 | # LoRa config 11 | PIN_ID_FOR_LORA_RESET = 33 12 | 13 | PIN_ID_FOR_LORA_SS = 32 14 | PIN_ID_SCK = 14 15 | PIN_ID_MOSI = 13 16 | PIN_ID_MISO = 12 17 | 18 | PIN_ID_FOR_LORA_DIO0 = 36 19 | PIN_ID_FOR_LORA_DIO1 = None 20 | PIN_ID_FOR_LORA_DIO2 = None 21 | PIN_ID_FOR_LORA_DIO3 = None 22 | PIN_ID_FOR_LORA_DIO4 = None 23 | PIN_ID_FOR_LORA_DIO5 = None 24 | 25 | 26 | # OLED config 27 | PIN_ID_FOR_OLED_RESET = 16 28 | PIN_ID_SDA = 4 29 | PIN_ID_SCL = 5 30 | OLED_I2C_ADDR = 0x3C 31 | OLED_I2C_FREQ = 100000 32 | OLED_WIDTH = 128 33 | OLED_HEIGHT = 64 34 | 35 | 36 | # ESP config 37 | ON_BOARD_LED_PIN_NO = 17 38 | ON_BOARD_LED_HIGH_IS_ON = False 39 | GPIO_PINS = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 40 | 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 41 | 23, 25, 26, 27, 32, 34, 35, 36, 37, 38, 39) 42 | 43 | #构造函数 44 | def __init__(self, 45 | pin_id_led = ON_BOARD_LED_PIN_NO, 46 | on_board_led_high_is_on = ON_BOARD_LED_HIGH_IS_ON, 47 | pin_id_reset = PIN_ID_FOR_LORA_RESET, 48 | blink_on_start = (2, 0.5, 0.5), 49 | oled_width = OLED_WIDTH, oled_height = OLED_HEIGHT, 50 | scl_pin_id = PIN_ID_SCL, sda_pin_id = PIN_ID_SDA, 51 | freq = OLED_I2C_FREQ): 52 | 53 | #复用构造函数 54 | controller_esp.Controller.__init__(self, 55 | pin_id_led, 56 | on_board_led_high_is_on, 57 | pin_id_reset, 58 | blink_on_start) 59 | 60 | self.reset_pin(self.prepare_pin(self.PIN_ID_FOR_OLED_RESET)) 61 | display_ssd1306_i2c.Display.__init__(self, 62 | width = oled_width, height = oled_height, 63 | scl_pin_id = scl_pin_id, sda_pin_id = sda_pin_id, 64 | freq = freq) 65 | self.show_text('Hello Makerfabs!',0,0,clear_first = False) 66 | self.show_text('Life is short!',0,16,clear_first = False) 67 | self.show_text('You need python!',0,32,clear_first = False) 68 | self.show_text('Makepython ESP32!',0,48,clear_first = False, show_now = True, hold_seconds = 1) 69 | 70 | 71 | 72 | def add_transceiver(self, 73 | transceiver, 74 | pin_id_ss = PIN_ID_FOR_LORA_SS, 75 | pin_id_RxDone = PIN_ID_FOR_LORA_DIO0, 76 | pin_id_RxTimeout = PIN_ID_FOR_LORA_DIO1, 77 | pin_id_ValidHeader = PIN_ID_FOR_LORA_DIO2, 78 | pin_id_CadDone = PIN_ID_FOR_LORA_DIO3, 79 | pin_id_CadDetected = PIN_ID_FOR_LORA_DIO4, 80 | pin_id_PayloadCrcError = PIN_ID_FOR_LORA_DIO5): 81 | 82 | transceiver.show_text = self.show_text 83 | transceiver.show_packet = self.show_packet 84 | transceiver.show_text_wrap = self.show_text_wrap 85 | transceiver.clear = self.clear 86 | transceiver.fill_rect = self.fill_rect 87 | 88 | return super().add_transceiver(transceiver, 89 | pin_id_ss, 90 | pin_id_RxDone, 91 | pin_id_RxTimeout, 92 | pin_id_ValidHeader, 93 | pin_id_CadDone, 94 | pin_id_CadDetected, 95 | pin_id_PayloadCrcError) 96 | 97 | 98 | def show_packet(self, payload_string, rssi = None): 99 | self.clear() 100 | line_idx = 0 101 | if rssi: 102 | self.show_text('RSSI: {}'.format(rssi), x = 0, y = line_idx * 10, clear_first = False, show_now = False) 103 | line_idx += 1 104 | self.show_text_wrap(payload_string, start_line = line_idx, clear_first = False) 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/workSpace/display_ssd1306_i2c.py: -------------------------------------------------------------------------------- 1 | 2 | # https://learn.adafruit.com/micropython-hardware-ssd1306-oled-display/software 3 | import time 4 | import machine 5 | import ssd1306 6 | 7 | 8 | class Display: 9 | 10 | def __init__(self, 11 | width = 128, height = 64, 12 | scl_pin_id = 5, sda_pin_id = 4, 13 | freq = 400000): 14 | 15 | self.width = width 16 | self.height = height 17 | self.i2c = machine.I2C(scl = machine.Pin(scl_pin_id, machine.Pin.OUT), 18 | sda = machine.Pin(sda_pin_id), 19 | freq = freq) 20 | self.display = ssd1306.SSD1306_I2C(width, height, self.i2c) 21 | self.show = self.display.show 22 | 23 | def fill_rect(self, x, y, w, h, c): 24 | self.display.fill_rect(x, y, w, h, c) 25 | self.display.show() 26 | 27 | 28 | def clear(self): 29 | self.display.fill(0) 30 | self.display.show() 31 | 32 | 33 | def show_text(self, text, x = 0, y = 0, clear_first = True, show_now = True, hold_seconds = 0): 34 | if clear_first: self.display.fill(0) 35 | self.display.text(text, x, y) 36 | if show_now: 37 | self.display.show() 38 | if hold_seconds > 0: time.sleep(hold_seconds) 39 | 40 | 41 | def wrap(self, text, start_line = 0, 42 | height_per_line = 8, width_per_char = 8, 43 | start_pixel_each_line = 0): 44 | 45 | chars_per_line = self.width//width_per_char 46 | max_lines = self.height//height_per_line - start_line 47 | lines = [(text[chars_per_line*line: chars_per_line*(line+1)], start_pixel_each_line, height_per_line*(line+start_line)) 48 | for line in range(max_lines)] 49 | 50 | return lines 51 | 52 | 53 | def show_text_wrap(self, text, 54 | start_line = 0, height_per_line = 8, width_per_char = 8, start_pixel_each_line = 0, 55 | clear_first = True, show_now = True, hold_seconds = 0): 56 | 57 | if clear_first: self.clear() 58 | 59 | for line, x, y in self.wrap(text, start_line, height_per_line, width_per_char, start_pixel_each_line): 60 | self.show_text(line, x, y, clear_first = False, show_now = False) 61 | 62 | if show_now: 63 | self.display.show() 64 | if hold_seconds > 0: time.sleep(hold_seconds) 65 | 66 | 67 | def show_datetime(self, year, month, day, hour, minute, second): 68 | datetime = [year, month, day, hour, minute, second] 69 | datetime_str = ["{0:0>2}".format(d) for d in datetime] 70 | 71 | self.show_text(text = '-'.join(datetime_str[:3]), 72 | x = 0, y = 0, clear_first = True, show_now = False) 73 | self.show_text(text = ':'.join(datetime_str[3:6]), 74 | x = 0, y = 10, clear_first = False, show_now = True) 75 | 76 | 77 | def show_time(self, year, month, day, hour, minute, second): 78 | self.show_datetime(year, month, day, hour, minute, second) 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/workSpace/lora_node.py: -------------------------------------------------------------------------------- 1 | 2 | from machine import Pin 3 | import time 4 | import config_lora 5 | import random 6 | import webserver 7 | try: 8 | import usocket as socket 9 | except: 10 | import socket 11 | 12 | 13 | #网关角色 14 | MODE_TRANSFER = 0 15 | MODE_RECEIVER = 1 16 | MODE_GATE = 2 17 | 18 | #节点类型 19 | NODE_SENSOR = 0 20 | NODE_RELAY = 1 21 | 22 | class Lora_Gate: 23 | 24 | def __init__(self, name, mode, lora, ip): 25 | self.name = name 26 | self.lora = lora 27 | self.mode = mode 28 | self.sensor_adc = 0 29 | self.relay_status = "UNKNOWN" 30 | self.flag = 0 31 | self.buff = "" 32 | self.ip = ip 33 | 34 | #模式配置 35 | def working(self): 36 | str_ip = self.ip 37 | self.lora.show_text_wrap(str_ip) 38 | print("MODE_GATE") 39 | self.set_callback(self.on_gate_receiver) 40 | self.lora.receive() 41 | self.gate_working() 42 | pass 43 | 44 | #设置回调任务 45 | def set_callback(self, callback_task): 46 | self.lora.onReceive(callback_task) 47 | 48 | #发送数据 49 | def sendMessage(self, message): 50 | self.lora.println(message) 51 | #print("Sending message:\n{}\n".format(message)) 52 | print("Sending message:") 53 | print(message) 54 | 55 | 56 | #网关模式 57 | def gate_working(self): 58 | self.sendMessage("empty") 59 | onoff = "OFF" 60 | print("prepare create socket") 61 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 62 | print("already create socket") 63 | s.bind(('', 80)) 64 | print("bind") 65 | s.listen(5) 66 | print("listen") 67 | 68 | while True: 69 | #阻塞,等待webserver请求 70 | conn, addr = s.accept() 71 | print('Got a connection from %s' % str(addr)) 72 | request = conn.recv(1024) 73 | request = str(request) 74 | print('Content = %s' % request) 75 | 76 | #解析请求并发送控制继电器指令 77 | R1_ON = request.find('/?R1=on') 78 | R1_OFF = request.find('/?R1=off') 79 | R2_ON = request.find('/?R2=on') 80 | R2_OFF = request.find('/?R2=off') 81 | R3_ON = request.find('/?R3=on') 82 | R3_OFF = request.find('/?R3=off') 83 | R4_ON = request.find('/?R4=on') 84 | R4_OFF = request.find('/?R4=off') 85 | if R1_ON == 6: 86 | print('R1 ON') 87 | onoff = 'R1ON' 88 | if R1_OFF == 6: 89 | print('R1 OFF') 90 | onoff = 'R1OFF' 91 | if R1_ON == 6: 92 | print('R2 ON') 93 | onoff = 'R2ON' 94 | if R2_OFF == 6: 95 | print('R2 OFF') 96 | onoff = 'R2OFF' 97 | if R3_ON == 6: 98 | print('R3 ON') 99 | onoff = 'R3ON' 100 | if R3_OFF == 6: 101 | print('R3 OFF') 102 | onoff = 'R3OFF' 103 | if R4_ON == 6: 104 | print('R4 ON') 105 | onoff = 'R4ON' 106 | if R4_OFF == 6: 107 | print('R4 OFF') 108 | onoff = 'R4OFF' 109 | 110 | temp_msg = "RELAY" + onoff 111 | self.sendMessage(temp_msg) 112 | 113 | #等待lora响应 114 | self.lora.receive() 115 | print("wait lora callback") 116 | 117 | #阻塞等待lora回调完毕 118 | #解析在回调中进行,结果放到对象的字符串里 119 | 120 | now = config_lora.millisecond() 121 | while(self.flag == 0): 122 | if config_lora.millisecond() - now > 3000: 123 | print("Callback time out.") 124 | break 125 | pass 126 | 127 | self.flag = 0 128 | print(self.buff) 129 | 130 | #没找到关闭回调的命令,手动发送个无意义的进入发送模式屏蔽回调 131 | self.sendMessage("empty") 132 | 133 | #响应web请求 134 | response = webserver.web_page(self.relay_status) 135 | conn.send('HTTP/1.1 200 OK\n') 136 | conn.send('Content-Type: text/html\n') 137 | conn.send('Connection: close\n\n') 138 | conn.sendall(response) 139 | conn.close() 140 | 141 | #显示到屏幕上 142 | 143 | 144 | #准备下一个循环 145 | 146 | 147 | #网关模式回调 148 | def on_gate_receiver(self, payload): 149 | print("On gate receive") 150 | rssi = self.lora.packetRssi() 151 | 152 | try: 153 | #print payload可知报文前4字节和后一字节无意义 154 | if int(payload[0]) == 255: 155 | length=len(payload)-1 156 | payload_string = str((payload[4:length]),'utf-8') 157 | else: 158 | payload_string = str(payload,'utf-8') 159 | print("Received message:\n{}".format(payload_string)) 160 | self.buff = payload_string 161 | self.relay_status = str(self.buff) 162 | self.flag = 1 163 | 164 | except Exception as e: 165 | print(e) 166 | print("with RSSI {}\n".format(rssi)) 167 | 168 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/workSpace/main.py: -------------------------------------------------------------------------------- 1 | 2 | # coding: utf-8 3 | #开机自动运行main.py,无重要内容 4 | import gc 5 | gc.collect() #回收内存 6 | 7 | import sx127x 8 | gc.collect() 9 | 10 | import test 11 | # import test_dual_channels as test 12 | gc.collect() 13 | test.main() #指向测试主函数 14 | 15 | 16 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/workSpace/ssd1306.py: -------------------------------------------------------------------------------- 1 | 2 | # MicroPython SSD1306 OLED driver, I2C and SPI interfaces 3 | 4 | from micropython import const 5 | import time 6 | import framebuf 7 | 8 | 9 | # register definitions 10 | SET_CONTRAST = const(0x81) 11 | SET_ENTIRE_ON = const(0xa4) 12 | SET_NORM_INV = const(0xa6) 13 | SET_DISP = const(0xae) 14 | SET_MEM_ADDR = const(0x20) 15 | SET_COL_ADDR = const(0x21) 16 | SET_PAGE_ADDR = const(0x22) 17 | SET_DISP_START_LINE = const(0x40) 18 | SET_SEG_REMAP = const(0xa0) 19 | SET_MUX_RATIO = const(0xa8) 20 | SET_COM_OUT_DIR = const(0xc0) 21 | SET_DISP_OFFSET = const(0xd3) 22 | SET_COM_PIN_CFG = const(0xda) 23 | SET_DISP_CLK_DIV = const(0xd5) 24 | SET_PRECHARGE = const(0xd9) 25 | SET_VCOM_DESEL = const(0xdb) 26 | SET_CHARGE_PUMP = const(0x8d) 27 | 28 | 29 | class SSD1306: 30 | def __init__(self, width, height, external_vcc): 31 | self.width = width 32 | self.height = height 33 | self.external_vcc = external_vcc 34 | self.pages = self.height // 8 35 | self.buffer = bytearray(self.pages * self.width) 36 | fb = framebuf.FrameBuffer(self.buffer, self.width, self.height, framebuf.MONO_VLSB) 37 | self.framebuf = fb 38 | # Provide methods for accessing FrameBuffer graphics primitives. This is a 39 | # workround because inheritance from a native class is currently unsupported. 40 | # http://docs.micropython.org/en/latest/pyboard/library/framebuf.html 41 | self.fill = fb.fill 42 | self.pixel = fb.pixel 43 | self.hline = fb.hline 44 | self.vline = fb.vline 45 | self.line = fb.line 46 | self.rect = fb.rect 47 | self.fill_rect = fb.fill_rect 48 | self.text = fb.text 49 | self.scroll = fb.scroll 50 | self.blit = fb.blit 51 | self.poweron() 52 | self.init_display() 53 | 54 | def init_display(self): 55 | for cmd in ( 56 | SET_DISP | 0x00, # off 57 | # address setting 58 | SET_MEM_ADDR, 0x00, # horizontal 59 | # resolution and layout 60 | SET_DISP_START_LINE | 0x00, 61 | SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 62 | SET_MUX_RATIO, self.height - 1, 63 | SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 64 | SET_DISP_OFFSET, 0x00, 65 | SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12, 66 | # timing and driving scheme 67 | SET_DISP_CLK_DIV, 0x80, 68 | SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1, 69 | SET_VCOM_DESEL, 0x30, # 0.83*Vcc 70 | # display 71 | SET_CONTRAST, 0xff, # maximum 72 | SET_ENTIRE_ON, # output follows RAM contents 73 | SET_NORM_INV, # not inverted 74 | # charge pump 75 | SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, 76 | SET_DISP | 0x01): # on 77 | self.write_cmd(cmd) 78 | self.fill(0) 79 | self.show() 80 | 81 | def poweroff(self): 82 | self.write_cmd(SET_DISP | 0x00) 83 | 84 | def contrast(self, contrast): 85 | self.write_cmd(SET_CONTRAST) 86 | self.write_cmd(contrast) 87 | 88 | def invert(self, invert): 89 | self.write_cmd(SET_NORM_INV | (invert & 1)) 90 | 91 | def show(self): 92 | x0 = 0 93 | x1 = self.width - 1 94 | if self.width == 64: 95 | # displays with width of 64 pixels are shifted by 32 96 | x0 += 32 97 | x1 += 32 98 | self.write_cmd(SET_COL_ADDR) 99 | self.write_cmd(x0) 100 | self.write_cmd(x1) 101 | self.write_cmd(SET_PAGE_ADDR) 102 | self.write_cmd(0) 103 | self.write_cmd(self.pages - 1) 104 | self.write_data(self.buffer) 105 | 106 | 107 | class SSD1306_I2C(SSD1306): 108 | def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False): 109 | self.i2c = i2c 110 | self.addr = addr 111 | self.temp = bytearray(2) 112 | super().__init__(width, height, external_vcc) 113 | 114 | def write_cmd(self, cmd): 115 | self.temp[0] = 0x80 # Co=1, D/C#=0 116 | self.temp[1] = cmd 117 | self.i2c.writeto(self.addr, self.temp) 118 | 119 | def write_data(self, buf): 120 | self.temp[0] = self.addr << 1 121 | self.temp[1] = 0x40 # Co=0, D/C#=1 122 | self.i2c.start() 123 | self.i2c.write(self.temp) 124 | self.i2c.write(buf) 125 | self.i2c.stop() 126 | 127 | def poweron(self): 128 | pass 129 | 130 | 131 | class SSD1306_SPI(SSD1306): 132 | def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): 133 | self.rate = 10 * 1024 * 1024 134 | dc.init(dc.OUT, value=0) 135 | res.init(res.OUT, value=0) 136 | cs.init(cs.OUT, value=1) 137 | self.spi = spi 138 | self.dc = dc 139 | self.res = res 140 | self.cs = cs 141 | super().__init__(width, height, external_vcc) 142 | 143 | def write_cmd(self, cmd): 144 | self.spi.init(baudrate=self.rate, polarity=0, phase=0) 145 | self.cs(1) 146 | self.dc(0) 147 | self.cs(0) 148 | self.spi.write(bytearray([cmd])) 149 | self.cs(1) 150 | 151 | def write_data(self, buf): 152 | self.spi.init(baudrate=self.rate, polarity=0, phase=0) 153 | self.cs(1) 154 | self.dc(1) 155 | self.cs(0) 156 | self.spi.write(buf) 157 | self.cs(1) 158 | 159 | def poweron(self): 160 | self.res(1) 161 | time.sleep_ms(1) 162 | self.res(0) 163 | time.sleep_ms(10) 164 | self.res(1) 165 | 166 | 167 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/workSpace/sx127x.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | import gc 3 | import config_lora 4 | 5 | 6 | PA_OUTPUT_RFO_PIN = 0 7 | PA_OUTPUT_PA_BOOST_PIN = 1 8 | 9 | 10 | # registers 11 | REG_FIFO = 0x00 12 | REG_OP_MODE = 0x01 13 | REG_FRF_MSB = 0x06 14 | REG_FRF_MID = 0x07 15 | REG_FRF_LSB = 0x08 16 | REG_PA_CONFIG = 0x09 17 | REG_LNA = 0x0c 18 | REG_FIFO_ADDR_PTR = 0x0d 19 | 20 | REG_FIFO_TX_BASE_ADDR = 0x0e 21 | FifoTxBaseAddr = 0x00 22 | # FifoTxBaseAddr = 0x80 23 | 24 | REG_FIFO_RX_BASE_ADDR = 0x0f 25 | FifoRxBaseAddr = 0x00 26 | REG_FIFO_RX_CURRENT_ADDR = 0x10 27 | REG_IRQ_FLAGS_MASK = 0x11 28 | REG_IRQ_FLAGS = 0x12 29 | REG_RX_NB_BYTES = 0x13 30 | REG_PKT_RSSI_VALUE = 0x1a 31 | REG_PKT_SNR_VALUE = 0x1b 32 | REG_MODEM_CONFIG_1 = 0x1d 33 | REG_MODEM_CONFIG_2 = 0x1e 34 | REG_PREAMBLE_MSB = 0x20 35 | REG_PREAMBLE_LSB = 0x21 36 | REG_PAYLOAD_LENGTH = 0x22 37 | REG_FIFO_RX_BYTE_ADDR = 0x25 38 | REG_MODEM_CONFIG_3 = 0x26 39 | REG_RSSI_WIDEBAND = 0x2c 40 | REG_DETECTION_OPTIMIZE = 0x31 41 | REG_DETECTION_THRESHOLD = 0x37 42 | REG_SYNC_WORD = 0x39 43 | REG_DIO_MAPPING_1 = 0x40 44 | REG_VERSION = 0x42 45 | 46 | # modes 47 | MODE_LONG_RANGE_MODE = 0x80 # bit 7: 1 => LoRa mode 48 | MODE_SLEEP = 0x00 49 | MODE_STDBY = 0x01 50 | MODE_TX = 0x03 51 | MODE_RX_CONTINUOUS = 0x05 52 | MODE_RX_SINGLE = 0x06 53 | 54 | # PA config 55 | PA_BOOST = 0x80 56 | 57 | # IRQ masks 58 | IRQ_TX_DONE_MASK = 0x08 59 | IRQ_PAYLOAD_CRC_ERROR_MASK = 0x20 60 | IRQ_RX_DONE_MASK = 0x40 61 | IRQ_RX_TIME_OUT_MASK = 0x80 62 | 63 | # Buffer size 64 | MAX_PKT_LENGTH = 255 65 | 66 | 67 | class SX127x: 68 | 69 | # The controller can be ESP8266, ESP32, Raspberry Pi, or a PC. 70 | # The controller needs to provide an interface consisted of: 71 | # 1. a SPI, with transfer function. 72 | # 2. a reset pin, with low(), high() functions. 73 | # 3. IRQ pinS , to be triggered by RFM96W's DIO0~5 pins. These pins each has two functions: 74 | # 3.1 set_handler_for_irq_on_rising_edge() 75 | # 3.2 detach_irq() 76 | # 4. a function to blink on-board LED. 77 | 78 | def __init__(self, 79 | name = 'SX127x', 80 | parameters = {'frequency': 433E6, 'tx_power_level': 2, 'signal_bandwidth': 125E3, #125E3 81 | 'spreading_factor': 7, 'coding_rate': 8, 'preamble_length': 8, 82 | 'implicitHeader': True, 'sync_word': 0x12, 'enable_CRC': True}, 83 | onReceive = None): 84 | 85 | self.name = name 86 | self.parameters = parameters 87 | self._onReceive = onReceive 88 | self._lock = False 89 | 90 | 91 | def init(self, parameters = None): 92 | if parameters: self.parameters = parameters 93 | 94 | # check version 95 | version = self.readRegister(REG_VERSION) 96 | print('version: ', version) 97 | if version != 0x12: 98 | raise Exception('Invalid version.') 99 | 100 | 101 | # put in LoRa and sleep mode 102 | self.sleep() 103 | 104 | 105 | # config 106 | self.setFrequency(self.parameters['frequency']) 107 | self.setSignalBandwidth(self.parameters['signal_bandwidth']) 108 | 109 | # set LNA boost 110 | self.writeRegister(REG_LNA, self.readRegister(REG_LNA) | 0x03) 111 | 112 | # set auto AGC 113 | self.writeRegister(REG_MODEM_CONFIG_3, 0x04) 114 | 115 | self.setTxPower(self.parameters['tx_power_level']) 116 | self._implicitHeaderMode = None 117 | self.implicitHeaderMode(self.parameters['implicitHeader']) 118 | self.setSpreadingFactor(self.parameters['spreading_factor']) 119 | self.setCodingRate(self.parameters['coding_rate']) 120 | self.setPreambleLength(self.parameters['preamble_length']) 121 | self.setSyncWord(self.parameters['sync_word']) 122 | self.enableCRC(self.parameters['enable_CRC']) 123 | 124 | # set LowDataRateOptimize flag if symbol time > 16ms (default disable on reset) 125 | # self.writeRegister(REG_MODEM_CONFIG_3, self.readRegister(REG_MODEM_CONFIG_3) & 0xF7) # default disable on reset 126 | 127 | #if 1000 / (self.parameters['signal_bandwidth'] / 2**self.parameters['spreading_factor']) > 16: 128 | # self.writeRegister(REG_MODEM_CONFIG_3, self.readRegister(REG_MODEM_CONFIG_3) | 0x08) 129 | 130 | # set base addresses 131 | self.writeRegister(REG_FIFO_TX_BASE_ADDR, FifoTxBaseAddr) 132 | self.writeRegister(REG_FIFO_RX_BASE_ADDR, FifoRxBaseAddr) 133 | 134 | self.standby() 135 | 136 | 137 | def beginPacket(self, implicitHeaderMode = False): 138 | self.standby() 139 | self.implicitHeaderMode(implicitHeaderMode) 140 | 141 | # reset FIFO address and paload length 142 | self.writeRegister(REG_FIFO_ADDR_PTR, FifoTxBaseAddr) 143 | self.writeRegister(REG_PAYLOAD_LENGTH, 0) 144 | 145 | 146 | def endPacket(self): 147 | # put in TX mode 148 | self.writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX) 149 | 150 | # wait for TX done, standby automatically on TX_DONE 151 | while (self.readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0: 152 | pass 153 | 154 | # clear IRQ's 155 | self.writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK) 156 | 157 | self.collect_garbage() 158 | 159 | 160 | def write(self, buffer): 161 | currentLength = self.readRegister(REG_PAYLOAD_LENGTH) 162 | size = len(buffer) 163 | 164 | # check size 165 | size = min(size, (MAX_PKT_LENGTH - FifoTxBaseAddr - currentLength)) 166 | 167 | # write data 168 | for i in range(size): 169 | self.writeRegister(REG_FIFO, buffer[i]) 170 | 171 | # update length 172 | self.writeRegister(REG_PAYLOAD_LENGTH, currentLength + size) 173 | return size 174 | 175 | 176 | def aquire_lock(self, lock = False): 177 | if not config_lora.IS_MICROPYTHON: # MicroPython is single threaded, doesn't need lock. 178 | if lock: 179 | while self._lock: pass 180 | self._lock = True 181 | else: 182 | self._lock = False 183 | 184 | 185 | def println(self, string, implicitHeader = False): 186 | self.aquire_lock(True) # wait until RX_Done, lock and begin writing. 187 | 188 | self.beginPacket(implicitHeader) 189 | b1 = bytes(b'\xff\xff\x00\x00') 190 | b2 = bytes(b'\x00') 191 | self.write(b1 + string.encode() + b2) 192 | self.endPacket() 193 | 194 | self.aquire_lock(False) # unlock when done writing 195 | 196 | 197 | def getIrqFlags(self): 198 | irqFlags = self.readRegister(REG_IRQ_FLAGS) 199 | self.writeRegister(REG_IRQ_FLAGS, irqFlags) 200 | return irqFlags 201 | 202 | 203 | def packetRssi(self): 204 | return (self.readRegister(REG_PKT_RSSI_VALUE) - (164 if self._frequency < 868E6 else 157)) 205 | 206 | 207 | def packetSnr(self): 208 | return (self.readRegister(REG_PKT_SNR_VALUE)) * 0.25 209 | 210 | 211 | def standby(self): 212 | self.writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY) 213 | 214 | 215 | def sleep(self): 216 | self.writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP) 217 | 218 | 219 | def setTxPower(self, level, outputPin = PA_OUTPUT_PA_BOOST_PIN): 220 | if (outputPin == PA_OUTPUT_RFO_PIN): 221 | # RFO 222 | level = min(max(level, 0), 14) 223 | self.writeRegister(REG_PA_CONFIG, 0x70 | level) 224 | 225 | else: 226 | # PA BOOST 227 | level = min(max(level, 2), 17) 228 | self.writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2)) 229 | 230 | 231 | def setFrequency(self, frequency): 232 | self._frequency = frequency 233 | 234 | frfs = {169E6: (42, 64, 0), 235 | 433E6: (108, 64, 0), 236 | 434E6: (108, 128, 0), 237 | 866E6: (216, 128, 0), 238 | 868E6: (217, 0, 0), 239 | 915E6: (228, 192, 0)} 240 | 241 | self.writeRegister(REG_FRF_MSB, frfs[frequency][0]) 242 | self.writeRegister(REG_FRF_MID, frfs[frequency][1]) 243 | self.writeRegister(REG_FRF_LSB, frfs[frequency][2]) 244 | 245 | 246 | def setSpreadingFactor(self, sf): 247 | sf = min(max(sf, 6), 12) 248 | self.writeRegister(REG_DETECTION_OPTIMIZE, 0xc5 if sf == 6 else 0xc3) 249 | self.writeRegister(REG_DETECTION_THRESHOLD, 0x0c if sf == 6 else 0x0a) 250 | self.writeRegister(REG_MODEM_CONFIG_2, (self.readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)) 251 | 252 | 253 | def setSignalBandwidth(self, sbw): 254 | bins = (7.8E3, 10.4E3, 15.6E3, 20.8E3, 31.25E3, 41.7E3, 62.5E3, 125E3, 250E3) 255 | 256 | bw = 9 257 | for i in range(len(bins)): 258 | if sbw <= bins[i]: 259 | bw = i 260 | break 261 | 262 | # bw = bins.index(sbw) 263 | 264 | self.writeRegister(REG_MODEM_CONFIG_1, (self.readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4)) 265 | 266 | 267 | def setCodingRate(self, denominator): 268 | denominator = min(max(denominator, 5), 8) 269 | cr = denominator - 4 270 | self.writeRegister(REG_MODEM_CONFIG_1, (self.readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)) 271 | 272 | 273 | def setPreambleLength(self, length): 274 | self.writeRegister(REG_PREAMBLE_MSB, (length >> 8) & 0xff) 275 | self.writeRegister(REG_PREAMBLE_LSB, (length >> 0) & 0xff) 276 | 277 | 278 | def enableCRC(self, enable_CRC = False): 279 | modem_config_2 = self.readRegister(REG_MODEM_CONFIG_2) 280 | config = modem_config_2 | 0x04 if enable_CRC else modem_config_2 & 0xfb 281 | self.writeRegister(REG_MODEM_CONFIG_2, config) 282 | 283 | 284 | def setSyncWord(self, sw): 285 | self.writeRegister(REG_SYNC_WORD, sw) 286 | 287 | 288 | # def enable_Rx_Done_IRQ(self, enable = True): 289 | # if enable: 290 | # self.writeRegister(REG_IRQ_FLAGS_MASK, self.readRegister(REG_IRQ_FLAGS_MASK) & ~IRQ_RX_DONE_MASK) 291 | # else: 292 | # self.writeRegister(REG_IRQ_FLAGS_MASK, self.readRegister(REG_IRQ_FLAGS_MASK) | IRQ_RX_DONE_MASK) 293 | 294 | 295 | # def dumpRegisters(self): 296 | # for i in range(128): 297 | # print("0x{0:02x}: {1:02x}".format(i, self.readRegister(i))) 298 | 299 | 300 | def implicitHeaderMode(self, implicitHeaderMode = False): 301 | if self._implicitHeaderMode != implicitHeaderMode: # set value only if different. 302 | self._implicitHeaderMode = implicitHeaderMode 303 | modem_config_1 = self.readRegister(REG_MODEM_CONFIG_1) 304 | config = modem_config_1 | 0x01 if implicitHeaderMode else modem_config_1 & 0xfe 305 | self.writeRegister(REG_MODEM_CONFIG_1, config) 306 | 307 | 308 | def onReceive(self, callback): 309 | self._onReceive = callback 310 | 311 | if self.pin_RxDone: 312 | if callback: 313 | self.writeRegister(REG_DIO_MAPPING_1, 0x00) 314 | self.pin_RxDone.set_handler_for_irq_on_rising_edge(handler = self.handleOnReceive) 315 | else: 316 | self.pin_RxDone.detach_irq() 317 | 318 | 319 | def receive(self, size = 0): 320 | self.implicitHeaderMode(size > 0) 321 | if size > 0: self.writeRegister(REG_PAYLOAD_LENGTH, size & 0xff) 322 | 323 | # The last packet always starts at FIFO_RX_CURRENT_ADDR 324 | # no need to reset FIFO_ADDR_PTR 325 | self.writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS) 326 | 327 | 328 | # on RPi, interrupt callback is threaded and racing with main thread, 329 | # Needs a lock for accessing FIFO. 330 | # https://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/ 331 | # http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-2 332 | def handleOnReceive(self, event_source): 333 | self.aquire_lock(True) # lock until TX_Done 334 | 335 | # irqFlags = self.getIrqFlags() should be 0x50 336 | if (self.getIrqFlags() & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0: 337 | if self._onReceive: 338 | payload = self.read_payload() 339 | self.aquire_lock(False) # unlock when done reading 340 | 341 | self._onReceive(payload) 342 | 343 | self.aquire_lock(False) # unlock in any case. 344 | 345 | 346 | def receivedPacket(self, size = 0): 347 | irqFlags = self.getIrqFlags() 348 | 349 | self.implicitHeaderMode(size > 0) 350 | if size > 0: self.writeRegister(REG_PAYLOAD_LENGTH, size & 0xff) 351 | 352 | # if (irqFlags & IRQ_RX_DONE_MASK) and \ 353 | # (irqFlags & IRQ_RX_TIME_OUT_MASK == 0) and \ 354 | # (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK == 0): 355 | 356 | if (irqFlags == IRQ_RX_DONE_MASK): # RX_DONE only, irqFlags should be 0x40 357 | # automatically standby when RX_DONE 358 | return True 359 | 360 | elif self.readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE): 361 | # no packet received. 362 | # reset FIFO address / # enter single RX mode 363 | self.writeRegister(REG_FIFO_ADDR_PTR, FifoRxBaseAddr) 364 | self.writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE) 365 | 366 | 367 | def read_payload(self): 368 | # set FIFO address to current RX address 369 | # fifo_rx_current_addr = self.readRegister(REG_FIFO_RX_CURRENT_ADDR) 370 | self.writeRegister(REG_FIFO_ADDR_PTR, self.readRegister(REG_FIFO_RX_CURRENT_ADDR)) 371 | 372 | # read packet length 373 | packetLength = self.readRegister(REG_PAYLOAD_LENGTH) if self._implicitHeaderMode else \ 374 | self.readRegister(REG_RX_NB_BYTES) 375 | 376 | payload = bytearray() 377 | for i in range(packetLength): 378 | payload.append(self.readRegister(REG_FIFO)) 379 | 380 | self.collect_garbage() 381 | return bytes(payload) 382 | 383 | 384 | def readRegister(self, address, byteorder = 'big', signed = False): 385 | response = self.transfer(self.pin_ss, address & 0x7f) 386 | return int.from_bytes(response, byteorder) 387 | 388 | 389 | def writeRegister(self, address, value): 390 | self.transfer(self.pin_ss, address | 0x80, value) 391 | 392 | 393 | def collect_garbage(self): 394 | gc.collect() 395 | if config_lora.IS_MICROPYTHON: 396 | print('[Memory - free: {} allocated: {}]'.format(gc.mem_free(), gc.mem_alloc())) 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/workSpace/test.py: -------------------------------------------------------------------------------- 1 | import sx127x 2 | import config_lora 3 | import lora_node 4 | import webserver 5 | 6 | 7 | 8 | def main(): 9 | ip = webserver.connect() 10 | 11 | controller = config_lora.Controller() 12 | lora = controller.add_transceiver(sx127x.SX127x(name = 'LoRa'), 13 | pin_id_ss = config_lora.Controller.PIN_ID_FOR_LORA_SS, 14 | pin_id_RxDone = config_lora.Controller.PIN_ID_FOR_LORA_DIO0) 15 | print('lora', lora) 16 | print("ready to create node") 17 | 18 | #node = lora_node.Lora_Node("xbw","001",1) 19 | #gate = lora_node.Lora_Gate("Master1", lora_node.MODE_RECEIVER, lora, node) 20 | 21 | #node = lora_node.Lora_Node("xbw","001",1) 22 | #gate = lora_node.Lora_Gate("Master1", lora_node.MODE_TRANSFER, lora, node) 23 | 24 | gate = lora_node.Lora_Gate("Master1", lora_node.MODE_GATE, lora, ip) 25 | 26 | gate.working() 27 | print("Error ,program over") 28 | 29 | 30 | if __name__ == '__main__': 31 | main() 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/Lora gateway cantrol/workSpace/webserver.py: -------------------------------------------------------------------------------- 1 | #webserver.py 2 | import network 3 | import webrepl 4 | import time 5 | from machine import Pin 6 | try: 7 | import usocket as socket 8 | except: 9 | import socket 10 | 11 | AUTH_OPEN = 0 12 | AUTH_WEP = 1 13 | AUTH_WPA_PSK = 2 14 | AUTH_WPA2_PSK = 3 15 | AUTH_WPA_WPA2_PSK = 4 16 | 17 | SSID = "Makerfabs" #Modify here with SSID 18 | PASSWORD = "20160704" #Modify here with PWD 19 | led = Pin(5, Pin.OUT) 20 | ip = "ip get wrong" 21 | 22 | def web_page(msg): 23 | html =""" 24 | 25 | 26 | 27 | LED Button 28 | 40 | 41 | 42 | 43 |

Lora Relay

44 |

Lora Relay status:""" + str(msg) + """

45 | 93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | 102 |
103 |
104 |
105 | 106 | """ 107 | return html 108 | 109 | def do_connect(ssid,psw): 110 | wlan = network.WLAN(network.STA_IF) 111 | wlan.active(True) 112 | s = wlan.config("mac") 113 | mac = ('%02x:%02x:%02x:%02x:%02x:%02x').upper() %(s[0],s[1],s[2],s[3],s[4],s[5]) 114 | print("Local MAC:"+mac) #get mac 115 | wlan.connect(ssid, psw) 116 | if not wlan.isconnected(): 117 | print('connecting to network...' + ssid) 118 | wlan.connect(ssid, psw) 119 | 120 | start = time.ticks_ms() # get millisecond counter 121 | while not wlan.isconnected(): 122 | time.sleep(1) # sleep for 1 second 123 | if time.ticks_ms()-start > 20000: 124 | print("connect timeout!") 125 | break 126 | 127 | if wlan.isconnected(): 128 | print('network config:', wlan.ifconfig()) 129 | global ip 130 | ip = str(wlan.ifconfig()) 131 | return wlan 132 | 133 | def connect(): 134 | do_connect(SSID,PASSWORD) 135 | global ip 136 | return ip 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /Hardware/4-Channel Lora Relay-10A v2.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Makerfabs/Lora-Relay-4Channel/86557990d2685f016c8d1867b68029fdb374fa86/Hardware/4-Channel Lora Relay-10A v2.0.pdf -------------------------------------------------------------------------------- /LoraReceiver/LoraReceiver.ino: -------------------------------------------------------------------------------- 1 | // Arduino9x_RX 2 | // -*- mode: C++ -*- 3 | // Example sketch showing how to create a simple messaging client (receiver) 4 | // with the RH_RF95 class. RH_RF95 class does not provide for addressing or 5 | // reliability, so you should only use RH_RF95 if you do not need the higher 6 | // level messaging abilities. 7 | // It is designed to work with the other example Arduino9x_TX 8 | 9 | #include 10 | #include 11 | 12 | #define RFM95_CS 10 13 | #define RFM95_RST 9 14 | #define RFM95_INT 2 15 | 16 | // Change to 868.0 or other frequency, must match RX's freq! 17 | #define RF95_FREQ 868.0 18 | 19 | // Singleton instance of the radio driver 20 | RH_RF95 rf95(RFM95_CS, RFM95_INT); 21 | 22 | // Blinky on receipt 23 | #define LED 5 24 | 25 | 26 | int count=0; 27 | 28 | void TurnOnRelay(void) 29 | { 30 | digitalWrite(4, HIGH); //RELAY 1 31 | digitalWrite(3, HIGH); //RELAY 2 32 | digitalWrite(A3, HIGH); //RELAY 3 33 | digitalWrite(A2, HIGH); //RELAY 4 34 | 35 | delay(100); 36 | } 37 | 38 | void TurnOffRelay(void) 39 | { 40 | digitalWrite(4, LOW); 41 | digitalWrite(3, LOW); 42 | digitalWrite(A3, LOW); 43 | digitalWrite(A2, LOW); 44 | 45 | 46 | delay(100); 47 | } 48 | 49 | void setup() 50 | { 51 | pinMode(5, OUTPUT); 52 | pinMode(4, OUTPUT); 53 | pinMode(3, OUTPUT); 54 | pinMode(A3, OUTPUT); 55 | pinMode(A2, OUTPUT); 56 | 57 | pinMode(RFM95_RST, OUTPUT); 58 | digitalWrite(RFM95_RST, HIGH); 59 | 60 | //while (!Serial); 61 | Serial.begin(115200); 62 | delay(100); 63 | 64 | Serial.println("Arduino LoRa RX Test!"); 65 | 66 | // manual reset 67 | digitalWrite(RFM95_RST, LOW); 68 | delay(10); 69 | digitalWrite(RFM95_RST, HIGH); 70 | delay(10); 71 | 72 | while (!rf95.init()) { 73 | Serial.println("LoRa radio init failed"); 74 | while (1); 75 | } 76 | Serial.println("LoRa radio init OK!"); 77 | 78 | // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM 79 | if (!rf95.setFrequency(RF95_FREQ)) { 80 | Serial.println("setFrequency failed"); 81 | while (1); 82 | } 83 | Serial.print("Set Freq to: "); Serial.println(RF95_FREQ); 84 | 85 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 86 | 87 | // The default transmitter power is 13dBm, using PA_BOOST. 88 | // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 89 | // you can set transmitter powers from 5 to 23 dBm: 90 | rf95.setTxPower(23, false); 91 | } 92 | 93 | void loop() 94 | { 95 | if (rf95.available()) 96 | { 97 | 98 | // Should be a message for us now 99 | uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; 100 | uint8_t len = sizeof(buf); 101 | 102 | if (rf95.recv(buf, &len)) 103 | { 104 | count++; 105 | digitalWrite(LED, HIGH); 106 | RH_RF95::printBuffer("Received: ", buf, len); 107 | Serial.print("Got: "); 108 | Serial.println((char*)buf); 109 | Serial.print("RSSI: "); 110 | Serial.println(rf95.lastRssi(), DEC); 111 | 112 | if(count%2==1) 113 | TurnOnRelay(); 114 | else 115 | TurnOffRelay(); 116 | 117 | // Send a reply 118 | uint8_t data[] = "And hello back to you"; 119 | rf95.send(data, sizeof(data)); 120 | rf95.waitPacketSent(); 121 | Serial.println("Sent a reply"); 122 | digitalWrite(LED, LOW); 123 | } 124 | else 125 | { 126 | Serial.println("Receive failed"); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /LoraTransmitter/LoraTransmitter.ino: -------------------------------------------------------------------------------- 1 | // LoRa 9x_TX 2 | // -*- mode: C++ -*- 3 | // Example sketch showing how to create a simple messaging client (transmitter) 4 | // with the RH_RF95 class. RH_RF95 class does not provide for addressing or 5 | // reliability, so you should only use RH_RF95 if you do not need the higher 6 | // level messaging abilities. 7 | // It is designed to work with the other example LoRa9x_RX 8 | 9 | #include 10 | #include 11 | 12 | #define RFM95_CS 10 13 | #define RFM95_RST 9 14 | #define RFM95_INT 2 15 | 16 | // Change to 868.0 or other frequency, must match RX's freq! 17 | #define RF95_FREQ 868.0 18 | 19 | // Singleton instance of the radio driver 20 | RH_RF95 rf95(RFM95_CS, RFM95_INT); 21 | 22 | void setup() 23 | { 24 | pinMode(RFM95_RST, OUTPUT); 25 | digitalWrite(RFM95_RST, HIGH); 26 | 27 | //while (!Serial); 28 | Serial.begin(115200); 29 | delay(100); 30 | 31 | Serial.println("Arduino LoRa TX Test!"); 32 | 33 | // manual reset 34 | digitalWrite(RFM95_RST, LOW); 35 | delay(10); 36 | digitalWrite(RFM95_RST, HIGH); 37 | delay(10); 38 | 39 | while (!rf95.init()) { 40 | Serial.println("LoRa radio init failed"); 41 | while (1); 42 | } 43 | Serial.println("LoRa radio init OK!"); 44 | 45 | // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM 46 | if (!rf95.setFrequency(RF95_FREQ)) { 47 | Serial.println("setFrequency failed"); 48 | while (1); 49 | } 50 | Serial.print("Set Freq to: "); Serial.println(RF95_FREQ); 51 | 52 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 53 | 54 | // The default transmitter power is 13dBm, using PA_BOOST. 55 | // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 56 | // you can set transmitter powers from 5 to 23 dBm: 57 | rf95.setTxPower(23, false); 58 | } 59 | 60 | int16_t packetnum = 0; // packet counter, we increment per xmission 61 | 62 | void loop() 63 | { 64 | Serial.println("Sending to rf95_server"); 65 | // Send a message to rf95_server 66 | 67 | char radiopacket[20] = "Hello World # "; 68 | itoa(packetnum++, radiopacket+13, 10); 69 | Serial.print("Sending "); Serial.println(radiopacket); 70 | radiopacket[19] = 0; 71 | 72 | Serial.println("Sending..."); delay(10); 73 | rf95.send((uint8_t *)radiopacket, 20); 74 | 75 | Serial.println("Waiting for packet to complete..."); delay(10); 76 | rf95.waitPacketSent(); 77 | // Now wait for a reply 78 | uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; 79 | uint8_t len = sizeof(buf); 80 | 81 | Serial.println("Waiting for reply..."); delay(10); 82 | if (rf95.waitAvailableTimeout(1000)) 83 | { 84 | // Should be a reply message for us now 85 | if (rf95.recv(buf, &len)) 86 | { 87 | Serial.print("Got reply: "); 88 | Serial.println((char*)buf); 89 | Serial.print("RSSI: "); 90 | Serial.println(rf95.lastRssi(), DEC); 91 | } 92 | else 93 | { 94 | Serial.println("Receive failed"); 95 | } 96 | } 97 | else 98 | { 99 | Serial.println("No reply, is there a listener around?"); 100 | } 101 | delay(1000); 102 | } 103 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | Lora-Relay-4Channel 2 | == 3 | Introduce 4 | - 5 | 4-Channel Lora Relay-10A based on the Arduino, users can program it with Arduino IDE, which is very easy especially suit for the none-programmers. There are also guide for users to learn how to create the first IoT project with this board, with which the starters can learn the hardware and programming skill quickly.
6 | [Makerfabs Wiki](https://makerfabs.com/wiki/index.php?title=Main_Page)
7 |
8 | 9 | Feature 10 | - 11 | * ATMEL Atmega328P: High Performance, Low Power Atmel®AVR® 8-Bit Microcontroller 12 | * Speed Grade:20Mhz 13 | * Flash:32Kbytes 14 | * RAM: 2KBytes 15 | * EEPROM: 1Kbytes 16 | * Relay type: General Purpose 17 | * Rated current of relay contact: 10A 18 | * Coil type of relay: Non Latching 19 | * Coil voltage of relay: 5V 20 | * Switching voltage of relay: (277VAC , 28VDC) Max 21 | * DC12V or 5V input 22 | 23 | Usage 24 | - 25 | ### Hardware connection 26 | The USB TO UART TOOL is needed to connect the module and PC.
27 | The pins connections is: 28 | |4-Channel Lora Relay-10A |USB-to-UART Tool | 29 | |---|---| 30 | |3V3 |3V3 | 31 | |GND |GND | 32 | |RX |TXD | 33 | |TX |RXD | 34 | 35 | ![](https://github.com/Makerfabs/Lora-Relay-4Channel/blob/master/md_pic/4-Channel%20Lora%20Relay-10A_3.jpg) 36 | 37 | ### Software setup 38 | Open the Arduino, select the tools menu and set the parameter, as the figure:
39 | ![](https://github.com/Makerfabs/Lora-Relay-4Channel/blob/master/md_pic/4-Channel%20Lora%20Relay-10A_4.png) 40 | 41 | ### Lora Transmitter 42 | Prepare a Lora receiver and put it aside.
43 | Open the code "LoraTransmitter/LoraTransmitter.ino" and modify the frequency macro according to your board is 433Mhz or 868Mhz or 915Mhz.
44 | ``` 45 | #define RF95_FREQ 868.0 46 | ``` 47 | Verify and upload it.
48 | ![](https://github.com/Makerfabs/Lora-Relay-4Channel/blob/master/md_pic/4-Channel%20Lora%20Relay-10A_8.png)
49 | Open the “Tools—Serial Monitor” and the information of Lora Transmitter will be shown in the monitor, as the picture. 50 | ![](https://github.com/Makerfabs/Lora-Relay-4Channel/blob/master/md_pic/4-Channel%20Lora%20Relay-10A_5.png) 51 | 52 | ### Lora receiver 53 | Open the "LoraReceiver/LoraReceiver.ino" and modify the frequency macro according to your board is 433Mhz or 868Mhz or 915Mhz. 54 | ``` 55 | #define RF95_FREQ 868.0 56 | ``` 57 | Verify and upload it. After finish, open the “Tools—Serial Monitor”, If have a transmitter next to it, the receive will receive data sent by the Transmitter and the monitor will show the received information in the window, as the picture. 58 | ![](https://github.com/Makerfabs/Lora-Relay-4Channel/blob/master/md_pic/4-Channel%20Lora%20Relay-10A_6.png)
59 | If the receiver has received it, the relay will be turned on or turned off. Light on when COM connect to NO, light off when COM connect to NC and Normally light off.
60 | ![](https://github.com/Makerfabs/Lora-Relay-4Channel/blob/master/md_pic/4-Channel%20Lora%20Relay-10A_7.gif)
61 | Control relay pins:
62 | |Atmega328P |Relay | 63 | |---|---| 64 | |D4 |K1 | 65 | |D3 |K2 | 66 | |A3 |K3 | 67 | |A2 |K4 | 68 | 69 | 70 | The following table lists all of the relay's pins and their functionality.
71 | |Pin |Description | 72 | |---|---| 73 | |NC Normally |Closed | 74 | |NO Normally |Opened | 75 | |COM |Switch Common | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /md_pic/4-Channel Lora Relay-10A_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Makerfabs/Lora-Relay-4Channel/86557990d2685f016c8d1867b68029fdb374fa86/md_pic/4-Channel Lora Relay-10A_1.jpg -------------------------------------------------------------------------------- /md_pic/4-Channel Lora Relay-10A_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Makerfabs/Lora-Relay-4Channel/86557990d2685f016c8d1867b68029fdb374fa86/md_pic/4-Channel Lora Relay-10A_3.jpg -------------------------------------------------------------------------------- /md_pic/4-Channel Lora Relay-10A_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Makerfabs/Lora-Relay-4Channel/86557990d2685f016c8d1867b68029fdb374fa86/md_pic/4-Channel Lora Relay-10A_4.png -------------------------------------------------------------------------------- /md_pic/4-Channel Lora Relay-10A_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Makerfabs/Lora-Relay-4Channel/86557990d2685f016c8d1867b68029fdb374fa86/md_pic/4-Channel Lora Relay-10A_5.png -------------------------------------------------------------------------------- /md_pic/4-Channel Lora Relay-10A_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Makerfabs/Lora-Relay-4Channel/86557990d2685f016c8d1867b68029fdb374fa86/md_pic/4-Channel Lora Relay-10A_6.png -------------------------------------------------------------------------------- /md_pic/4-Channel Lora Relay-10A_7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Makerfabs/Lora-Relay-4Channel/86557990d2685f016c8d1867b68029fdb374fa86/md_pic/4-Channel Lora Relay-10A_7.gif -------------------------------------------------------------------------------- /md_pic/4-Channel Lora Relay-10A_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Makerfabs/Lora-Relay-4Channel/86557990d2685f016c8d1867b68029fdb374fa86/md_pic/4-Channel Lora Relay-10A_8.png --------------------------------------------------------------------------------