├── .gitignore
├── LICENSE
├── README.md
├── parts_built_together.png
├── shutterserial.png
├── shutterserver.png
└── src
├── credentials.h
├── main.ino
└── vars.h
/.gitignore:
--------------------------------------------------------------------------------
1 | stepper_32v5_en/
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Carl
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ESP32Stepper for Domoticz with Web server
2 | USE Stepper Motor with ESP32
3 |
4 | Use a Steppermotor through Wifi and conrtol it with Domoticz or from your browser.
5 | For use in Domoticz change the url to http://{ip_address}/api/stepper/..... this will result in a sinlge line reply
6 |
7 | All versions have control through jQuery and layout with Bootstrap and Fontawesome.
8 |
9 | Soon MQTT will be included.
10 |
11 | ## Updates
12 |
13 | |Date|Description|
14 | |--|--|
15 | |19th August 2018|Update code with more structure
16 | |16th August 2018|Fixed typo in Pin names amd fixed endedAT to currPos|
17 | |8th August 2018|Added EEprom store of maximum steps|
18 | |4th April 2018|Graphical|
19 |
20 | ## Screenshots
21 | #### Display type: webserver
22 | 
23 |
24 | #### Display type: Arduino monitor
25 | 
26 |
27 |
28 | ## Materials to use
29 | Board: DOIT ESP32 DEVKIT V1, 80Mhz, 4MB(32Mhz),921600 None op COM3 Available at Banggood
30 |
31 | Driver: A4988 Driver Available at Banggood
32 |
33 | Stepper: type 17HS1362-P4130 Available at Banggood
34 |
35 | HAL Sensor: ADAFruit Digital Available at Banggood or at Digikey
36 |
37 | Capacitor: 100uF, 25V
38 |
39 | PowerSupply(1): 5 Volt Available at Banggood
40 |
41 | PowerSupply(2): 12 Volt Available at Banggood
42 |
43 | ## Where to obtain the parts and materials
44 | Banggood is where I buy all my parts Visit Banggood
45 |
46 | ## Wired connections
47 |
48 | |From|To|
49 | |---|---|
50 | |**ESP Module**||
51 | |ESP32 VIN| -> +5V (1)|
52 | |ESP32 GND| -> GROUND (1)|
53 | |ESP32 D12| -> LED -> Resistor 1K -> Ground|
54 | |ESP32 D18| -> A4988 Direction|
55 | |ESP32 D19| -> A4988 Step|
56 | |ESP32 D34| -> HAL Sensor D0|
57 | |**HAL or REED Sensor**||
58 | |HAL Sensor VCC| -> +5V (1)|
59 | |HAL Sensor GND| -> GROUND (1)|
60 | |**A4988 Stepper Module**||
61 | |A4988 SLEEP| -> A4988 RESET|
62 | |A4988 GND| -> GROUND (1)|
63 | |A4988 VCC| -> 5V (1)|
64 | |A4988 1B| -> Stepper RED|
65 | |A4988 1A| -> Stepper BLUE|
66 | |A4988 2A| -> Stepper GREEN|
67 | |A4988 2B| -> Stepper BLACK|
68 | |A4988 GND| -> GROUND 2|
69 | |A4988 VMOT| -> +12V (2)|
70 | |**Parts**||
71 | |Capacitor+| -> +12V (2)|
72 | |Capacitor-| -> GROUND (2)|
73 |
74 | ```
75 | /*
76 | #ESP32 Web Server to Control Stepper motor
77 | new version 19 April 2018
78 | Board: DOIT ESP32 DEVKIT V1, 80Mhz, 4MB(32Mhz),921600 None op COM3
79 | Driver: A4988 Driver
80 | Stepper: type 17HS1362-P4130
81 | */
82 |
83 | ```
84 | ## Project Photo
85 | #### Display type: All together
86 | 
87 |
88 | ## MIT License
89 |
90 | Copyright (c) 2018 SpoturDeal | Carl
91 |
92 | Permission is hereby granted, free of charge, to any person obtaining a copy
93 | of this software and associated documentation files (the "Software"), to deal
94 | in the Software without restriction, including without limitation the rights
95 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
96 | copies of the Software, and to permit persons to whom the Software is
97 | furnished to do so, subject to the following conditions:
98 |
99 | The above copyright notice and this permission notice shall be included in all
100 | copies or substantial portions of the Software.
101 |
102 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
103 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
104 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
105 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
106 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
107 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
108 | SOFTWARE.
109 |
--------------------------------------------------------------------------------
/parts_built_together.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpoturDeal/ESP32Stepper/705d1646070bb33ea39d59596d9574e92acb7205/parts_built_together.png
--------------------------------------------------------------------------------
/shutterserial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpoturDeal/ESP32Stepper/705d1646070bb33ea39d59596d9574e92acb7205/shutterserial.png
--------------------------------------------------------------------------------
/shutterserver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpoturDeal/ESP32Stepper/705d1646070bb33ea39d59596d9574e92acb7205/shutterserver.png
--------------------------------------------------------------------------------
/src/credentials.h:
--------------------------------------------------------------------------------
1 | // here are the credentials you need in your sketch
2 |
3 | // ip_MQTT could be an IP address or a server name like broker.example.com
4 | // if you use a different port for your MQTT set the proper port
5 | // OTA makes it possible to update over the air without pressing a button
6 |
7 |
8 | // WIFI (leave empty if you want to set by browser)
9 |
10 | #define my_SSID "***YOUR SSID***" // ssid of your accesspoint
11 | #define my_PASSWORD "***YOUR_PASSWORD***" // password of access point
12 |
13 | // ACCESS POINT
14 |
15 | #define ap_SSID "Esp32AP_ROLL" // not shown or unsecured when secret is too short
16 | #define ap_SECRET "hellolol" // minimum length of secret is 8 characters
17 |
18 | // MQTT
19 |
20 | #define ip_MQTT "192.168.xxx.xxx"
21 | #define port_MQTT 1883
22 | #define my_MQTT_USER "***YOUR_MQTT_USERNAME" // user for the mqtt server
23 | #define my_MQTT_PW "**YOUR_MQTT_PASSWORD" // password of mqtt
24 |
25 | // OTA
26 |
27 | #define my_OTA_PW "***YOUR_OTA_PASSWORD" // password for OTA updates
28 |
29 |
--------------------------------------------------------------------------------
/src/main.ino:
--------------------------------------------------------------------------------
1 | /*
2 | #ESP32 Web Server to Control Stepper motor
3 | new version 19 August 2018
4 | Board: DOIT ESP32 DEVKIT V1, 80Mhz, 4MB(32Mhz),921600 None op COM3
5 | Driver: A4988 Driver
6 | Stepper: type 17HS1362-P4130
7 | */
8 | #include
9 | #include
10 | #include
11 | #include "credentials.h"
12 | #include "vars.h"
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | // choose the ntp server that serves your timezone
19 | #define NTP_OFFSET 2 * 60 * 60 // In seconds
20 | #define NTP_INTERVAL 60 * 1000 // In miliseconds
21 | #define NTP_ADDRESS "ntp2.xs4all.nl" // NTP SERVER
22 |
23 | WiFiUDP ntpUDP;
24 | NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);
25 |
26 | WiFiServer server(80);
27 |
28 | void setup()
29 | {
30 | Serial.begin(115200);
31 | EEPROM.begin(32); // start EEprom
32 | setupPinModes();
33 | // We start by connecting to a WiFi network
34 | Serial.println();
35 | Serial.print("Connecting to ");
36 | Serial.println(ssid);
37 | // Wifi with
38 | WiFi.mode(WIFI_STA);
39 | WiFi.begin(ssid, password);
40 | while (WiFi.waitForConnectResult() != WL_CONNECTED) {
41 | Serial.println("Connection Failed! Rebooting...");
42 | delay(5000);
43 | ESP.restart();
44 | }
45 | setupOTA();
46 | initSettings();
47 |
48 | // start server and time client
49 | server.begin();
50 | timeClient.begin();
51 | // Blink onboard LED to signify its connected
52 | blink(3);
53 | }
54 |
55 |
56 | void loop(){
57 | // if OTA called we need this
58 | ArduinoOTA.handle();
59 | WiFiClient client = server.available(); // listen for incoming clients
60 | timeClient.update();
61 | formattedTime = timeClient.getFormattedTime();
62 | resetESPdaily();
63 | if (client) {
64 | while (client.connected()) {
65 | if (client.available()) { // if there's client data
66 | respMsg = "Current position = " + String(currPos); // HTTP Response Message
67 | // Read the first line of the request
68 | String req = client.readStringUntil('\r');
69 | processRequest(client,req);
70 |
71 | String s = userResponsePage(req);
72 | // Send the response to the client (browser)
73 | client.print(s);
74 | delay(1);
75 | break;
76 | } // client.available
77 | } //client.connected
78 | } //client
79 | }
80 |
81 |
82 |
83 | void blink(int blinks) {
84 | for (int i = 0; i <= blinks;i++){
85 | digitalWrite(LED, HIGH);
86 | delay(300);
87 | digitalWrite(LED, LOW);
88 | delay(300);
89 | }
90 | }
91 | int getValue(String req) {
92 | // check for question mark
93 | int val_start = req.indexOf('?');
94 | if (val_start ==-1) {
95 | //if they forget ? check for =
96 | val_start = req.indexOf('=');
97 | }
98 | // check if request is closed by /
99 | int val_end = req.indexOf('/',val_start);
100 | if (val_end== -1){
101 | // if not closed by / the chck for end of line (gives aan HTTP at the end????)
102 | val_end = req.length();
103 | }
104 | if (val_start == -1 || val_end == -1) {
105 | if (debugPrint ==true){
106 | Serial.print("Invalid request: ");
107 | Serial.println(req);
108 | }
109 | return(0);
110 | }
111 | req = req.substring(val_start + 1, val_end);
112 | if (debugPrint ==true){
113 | Serial.print("Request steps: ");
114 | Serial.println(req);
115 | }
116 | return(req.toInt());
117 | }
118 | void initSettings(){
119 | Serial.println("");
120 | Serial.println("WiFi connected");
121 | Serial.println("IP address: ");
122 | Serial.println(WiFi.localIP());
123 | Serial.println("Place this IP address into a browser window");
124 | // make an ip address you can read
125 | IPAddress myIP = WiFi.localIP();
126 | ipStr = String(myIP[0])+"."+String(myIP[1])+"."+String(myIP[2])+"."+String(myIP[3]);
127 |
128 | // get the values from EEprom
129 | // first the maximum number of steps that can be done
130 | EEPROM.get(EEmaxSteps,testVar);
131 | if (testVar > 0){
132 | maxSteps=testVar;
133 | }
134 | // get the last set position
135 | EEPROM.get(EEcurrStep,testVar);
136 | if (testVar > 0){
137 | currPos=testVar;
138 | } else {
139 | currPos=0;
140 | }
141 | // move the shutter to start position
142 | EEPROM.get(EEsetInit,testVar);
143 | if (testVar == 0){
144 | //currPos=maxSteps;
145 | rollDown(400);
146 | rollUp(maxSteps);
147 | noInit = false;
148 | }
149 | }
150 | String printUsage() {
151 | // Prepare the usage response here is ipStr used to show a proper IP address
152 | String s = "
Stepper usage
";
153 | s += "[Omhoog] http://"+ipStr+"/stepper/moveup?" + String(maxSteps) + " ";
154 | s += "[Omlaag] http://"+ipStr+"/stepper/movedown?" + String(maxSteps) + " ";
155 | s += "[Percentage] http://"+ipStr+"/stepper/percent?50 ";
156 | s += "[Max stappen] http://"+ipStr+"/stepper/setup?2200 ";
157 | s += "[Initialiseer] http://"+ipStr+"/stepper/init?0 ";
158 | s += "[Herstart] http://"+ipStr+"/stepper/restart ";
159 | s += "
Maximum number steps is " + String(maxSteps)+" (percent) .. Percentage is 1 (Open) to 100 (Closed) (init) .. 1 = done, 0 = do again
";
160 | return(s);
161 | }
162 | void processRequest(WiFiClient client,String req){
163 | if (debugPrint ==true){
164 | Serial.println(req);
165 | }
166 | if (req.indexOf("/stepper/movedown") != -1) {
167 | int stepsToDo = getValue(req);
168 | if (stepsToDo < 1 || stepsToDo > maxSteps || stepsToDo == 0) {
169 | respMsg = "ERROR: steps out of range 1 to "+ String(maxSteps);
170 | } else {
171 | rollDown(stepsToDo);
172 | respMsg = "OK: Steps done = " + String(stepsToDo) + " current position =" + String(currPos);
173 | }
174 | } else if (req.indexOf("/stepper/moveup") != -1) {
175 | int stepsToDo = getValue(req);
176 | if (stepsToDo < 1 || stepsToDo > maxSteps || stepsToDo == 0) {
177 | respMsg = "ERROR: steps out of range 1 to "+ String(maxSteps);
178 | } else {
179 | rollUp(stepsToDo);
180 | respMsg = "OK: Steps done = " + String(stepsToDo) + " current position =" + String(currPos);
181 | }
182 | } else if (req.indexOf("/stepper/percent") != -1) {
183 | int toPerc = getValue(req);
184 | if (toPerc > 100 || toPerc < 1) {
185 | respMsg = "ERROR: percentage out of range 1 to 100";
186 | } else {
187 | int exSteps = ((maxSteps/100)*toPerc)-currPos;
188 | if (exSteps > 1){
189 | rollDown(exSteps);
190 | respMsg = "OK: Steps done down = " + String(exSteps) + " current position =" + String(currPos);
191 | } else {
192 | exSteps=abs(exSteps);
193 | rollUp(exSteps);
194 | respMsg = "OK: Steps done up = " + String(exSteps) + " current position =" + String(currPos);
195 | }
196 | }
197 | } else if (req.indexOf("/stepper/setup") != -1) {
198 | maxSteps = getValue(req);
199 | // Store the maximum number of steps
200 | writeData(EEmaxSteps,maxSteps);
201 | respMsg = "OK: Maximum steps set at: " + String(maxSteps);
202 | } else if (req.indexOf("/stepper/init") != -1) {
203 | // Init is used to set the start position
204 | int initSet = getValue(req);
205 | writeData(EEsetInit,initSet);
206 | respMsg = "[" + formattedTime + "] OK: Initialisation set for: " + String(initSet);
207 | } else if (req.indexOf("/stepper/restart") != -1) {
208 | // manually restart the ESP32
209 | ESP.restart();
210 | }
211 | }
212 | void resetESPdaily(){
213 | // once a day do a restart if noInit in not false is. (sometimes the esp hangs up)
214 | if (formattedTime=="00:00:02" && noInit == true){
215 | ESP.restart();
216 | }
217 | }
218 | void rollDown(int doSteps) {
219 | digitalWrite(EnablePin, LOW);
220 | digitalWrite(DirPin, LOW);
221 | for (int i=1; i <= doSteps; i++){
222 | currPos++;
223 | int dnPin = digitalRead(ZMin);
224 | if ((Mechanical_Endstop == 1 && dnPin == LOW) || currPos >= maxSteps){
225 | currPos=maxSteps;
226 | break;
227 | }
228 | else if ((Mechanical_Endstop == 0 && dnPin == HIGH) || currPos >= maxSteps){
229 | currPos=maxSteps;
230 | break;
231 | }
232 | digitalWrite(StepPin, HIGH);
233 | delayMicroseconds(motorSpeed);
234 | digitalWrite(StepPin,LOW );
235 | delayMicroseconds(motorSpeed);
236 | }
237 | digitalWrite(EnablePin, HIGH);
238 | if (debugPrint ==true){
239 | Serial.println("Down to position " + String(currPos));
240 | }
241 | stopRoll();
242 | }
243 | void rollUp(int doSteps) {
244 | digitalWrite(EnablePin, LOW);
245 | digitalWrite(DirPin, HIGH);
246 | for (int i=1; i <= doSteps; i++){
247 | currPos--;
248 | int upPin = digitalRead(ZMax);
249 | if ((Mechanical_Endstop == 1 && upPin == LOW) || currPos < 5){
250 | currPos=0;
251 | break;
252 | }
253 | else if ((Mechanical_Endstop == 0 && upPin == HIGH) || currPos < 5){
254 | currPos=0;
255 | break;
256 | }
257 | digitalWrite(StepPin, HIGH);
258 | delayMicroseconds(motorSpeed);
259 | digitalWrite(StepPin,LOW );
260 | delayMicroseconds(motorSpeed);
261 |
262 | }
263 | digitalWrite(EnablePin, HIGH);
264 | if (debugPrint ==true){
265 | Serial.println("up to position " + String(currPos));
266 | }
267 | stopRoll();
268 | }
269 | void setupOTA(){
270 | ArduinoOTA.setHostname("ESP32_Stepper"); // Hostname for OTA
271 | ArduinoOTA.setPassword(my_OTA_PW); // set in credidentials.h
272 | ArduinoOTA
273 | .onStart([]() {
274 | String type;
275 | if (ArduinoOTA.getCommand() == U_FLASH)
276 | type = "sketch";
277 | else // U_SPIFFS
278 | type = "filesystem";
279 |
280 | // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
281 | Serial.println("Start updating " + type);
282 | })
283 | .onEnd([]() {
284 | Serial.println("\nEnd");
285 | })
286 | .onProgress([](unsigned int progress, unsigned int total) {
287 | Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
288 | })
289 | .onError([](ota_error_t error) {
290 | Serial.printf("Error[%u]: ", error);
291 | if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
292 | else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
293 | else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
294 | else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
295 | else if (error == OTA_END_ERROR) Serial.println("End Failed");
296 | });
297 |
298 | ArduinoOTA.begin(); // Start OTA
299 | }
300 | void setupPinModes(){
301 | pinMode(DirPin, OUTPUT); // set Stepper direction pin mode
302 | pinMode(StepPin, OUTPUT); // set Stepper step mode
303 | pinMode(EnablePin, OUTPUT); // set Stepper enable pin
304 | pinMode(MicroStep1Pin, OUTPUT); //set Microstep 1 config
305 | pinMode(MicroStep2Pin, OUTPUT); //set Microstep 2 config
306 | pinMode(MicroStep3Pin, OUTPUT); //set Microstep 3 config
307 | pinMode(ZMax, INPUT); // set top detection
308 | pinMode(ZMin, INPUT); // set down detection
309 | pinMode(LED, OUTPUT); // ready LED
310 |
311 | digitalWrite(MicroStep1Pin, LOW); // Initialized with microstepping off
312 | digitalWrite(MicroStep2Pin, LOW); // Initialized with microstepping off
313 | digitalWrite(MicroStep3Pin, LOW); // Initialized with microstepping off
314 | }
315 | void stopRoll(){
316 | // write current position to EEprom
317 | writeData(EEcurrStep,currPos);
318 | if (debugPrint ==true){
319 | Serial.println("Stop");
320 | }
321 | digitalWrite(EnablePin, LOW);
322 | digitalWrite(DirPin, HIGH);
323 | delay(1000);
324 | digitalWrite(EnablePin, HIGH);
325 | }
326 | String userResponsePage(String req){
327 | // Prepare the response
328 | String ui= "Something went wrong";
329 | if (req.indexOf("/api/") == -1){
330 | ui = "";
331 | ui += "";
332 | ui +="";
333 | ui += "