-->
Page 1 of 1

NodeMCU Wireless Dimmer Webpage

PostPosted: Thu Jun 10, 2021 3:05 am
by alaa85
Hi Everyone

I'm a nope when it comes to ESP8266, I'm trying to make an wireless dimmer with webpage control (not IoT) so I can control appliances without internet, I found one project looks good for me( electronic wise) I made all connections, when I upload the Sketch, and navigate to the IP address i get ("Not found: /") I've tried to contact the author with no luck, i looked in the Sketch and no webpage found or any indication on the webpage, can any one help me on understanding this code and to make it work, many thanks in advanced.
''' Dimmer.ino

#include "hw_timer.h"
#include "dimmer.h"

void setup()
{
Serial.begin(115200);

pinMode(ZERO_CROSSING_INT_PIN,INPUT);

for(int i=0; i<NUM_CHANNELS; i++)
{
pinMode(Drive_Pin[i],OUTPUT);
digitalWrite(Drive_Pin[i],LOW);
}

connectToWiFi();

WebSocketConnect();
MDNSConnect();
HTTPUpdateConnect();


noInterrupts();

timer_init();
attachInterrupt(ZERO_CROSSING_INT_PIN,Zero_Crossing_Int,RISING);

interrupts();
}


void loop()
{

if(millis() - lastConnectivityCheckTime > 1000)
{
if(WiFi.status() != WL_CONNECTED)
{
connectToWiFi();
WebSocketConnect();
MDNSConnect();
}
lastConnectivityCheckTime = millis();
}

else
{
webSocket.loop();
//yield();

//OTA
if (millis() - lastTimeHost > 10)
{
httpServer.handleClient();
lastTimeHost = millis();
}

//Update Connected Clients
currentChangeTime = millis();
if(currentChangeTime - lastChangeTime> 300 && isSynced == 0)
{
String websocketStatusMessage = "A" + String(Dimming_Lvl[0]) + ",B" + String(Dimming_Lvl[1]) + ",X" + String(State[0]) + ",Y" + String(State[1]);
webSocket.broadcastTXT(websocketStatusMessage); // Tell all connected clients current state of the channels
isSynced = 1;
}
}
}

'''
Dimmer.h

/*
Interrupt supported on all pins except GPIO16
Interrupt Modes :RISING,FALLING,CHANGE

Pins:
GPIO 5 : Driving the MOSFET/TRIAC Channel(0)
GPIO 4 : Driving the MOSFET/TRIAC Channel(1)
Further channels can be added as required..

GPIO 12 : Zero Crossing Interrupt

GPIO 0 GPIO 2 Boot Mode
H H FLASH
L H Program via UART(Rx,Tx)
*/

#define IS_DEBUG
#ifdef IS_DEBUG
#define DEBUG_PRINT(x) Serial.print(x)
#define DEBUG_PRINTLN(x) Serial.println(x)
#else
#define DEBUG_PRINT(x)
#endif

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>
#include <Arduino.h>
#include <WebSocketsServer.h>
#include <Hash.h>

WebSocketsServer webSocket = WebSocketsServer(81);
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;

///////////////////////////////////////////////////////////////////DEVICE CONFIG////////////////////////////////////////////////////////////////////

#define NUM_CHANNELS 2
#define ZERO_CROSSING_INT_PIN 12
#define DELTA 4 //(t_zero_crossing - t_interrupt)/STEP_TIME
#define STEP_TIME 78 //for 128 lvls (in uS) (65 for 50 Hz)

//128 lvl brightness control
int Dimming_Lvl[NUM_CHANNELS] = {0,0}; //(0-127)

int Drive_Pin[NUM_CHANNELS] = {5,4};
int State[NUM_CHANNELS] = {0,0};

//Wifi Access Point Settings
String ssid = "#Stay_Home";
String password = "Stiff@Wood";

volatile boolean isHandled[NUM_CHANNELS] = {0,0};
volatile int Lvl_Counter[NUM_CHANNELS] = {0,0};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned long lastConnectivityCheckTime = 0;
unsigned long lastTimeHost = 0;
unsigned long currentChangeTime = 0;
unsigned long lastChangeTime = 0;
boolean isSynced = 0;

int NumActiveChannels = 0;
volatile boolean zero_cross = 0;
volatile int NumHandled = 0;

//Wifi AP Settings
/* Set these to your desired credentials. */
const char *APssid = "Dimmer001";
const char *APpassword = "MagpieRobin";

const char* host = "Dimmer0";
/**
///////////////////////////////////////////////////////////////////////////// Update the state of a channel /////////////////////////////////////////////////////////////////////////////
**/
void Update_State(int ON_OFF,int Channel_Number)
{
if(State[Channel_Number] == 0 && ON_OFF == 1)
{
NumActiveChannels++;
}
else if(State[Channel_Number] == 1 && ON_OFF == 0)
{
NumActiveChannels--;
}
State[Channel_Number] = ON_OFF;
}


// WebSocket Events
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {

switch (type) {
case WStype_DISCONNECTED:
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
lastChangeTime = millis();
isSynced = 0;
DEBUG_PRINTLN(ip);
}
break;

case WStype_TEXT:
{
String text = String((char *) &payload[0]);
lastChangeTime = millis();
isSynced = 0;

if(text.startsWith("a"))
{
String aVal=(text.substring(text.indexOf("a")+1,text.length()));
int Lvl_0 = aVal.toInt();
Dimming_Lvl[0] = Lvl_0;
DEBUG_PRINTLN(Lvl_0);
}

if(text.startsWith("b"))
{
String bVal=(text.substring(text.indexOf("b")+1,text.length()));
int Lvl_1 = bVal.toInt();
Dimming_Lvl[1] = Lvl_1;
DEBUG_PRINTLN(Lvl_1);
}

if(text=="ON_0")
{
Update_State(1,0);
DEBUG_PRINTLN("Channel 0 ON!!");
}

if(text=="OFF_0")
{
Update_State(0,0);
digitalWrite(Drive_Pin[0], LOW);
DEBUG_PRINTLN("Channel 0 OFF!!");
}

if(text=="ON_1")
{
Update_State(1,1);
DEBUG_PRINTLN("Channel 1 ON!!");
}

if(text=="OFF_1")
{
Update_State(0,1);
digitalWrite(Drive_Pin[1], LOW);
DEBUG_PRINTLN("Channel 1 OFF!!");
}
}
//webSocket.sendTXT(num, payload, length);
//webSocket.broadcastTXT(payload, length);
break;

case WStype_BIN:
hexdump(payload, length);
//webSocket.sendBIN(num, payload, length);
break;
}
}


// WebSocket Connection
void WebSocketConnect()
{
webSocket.begin();
webSocket.onEvent(webSocketEvent);
}

// MDNS
void MDNSConnect()
{
if (!MDNS.begin(host))
{
DEBUG_PRINTLN("Error setting up MDNS responder!");
while (1)
{
delay(1000);
}
}
DEBUG_PRINTLN("mDNS responder started");
MDNS.addService("ws", "tcp", 81);
MDNS.addService("http", "tcp", 80);
}

// HTTP updater connection
void HTTPUpdateConnect()
{
httpUpdater.setup(&httpServer);
httpServer.begin();
DEBUG_PRINTLN("HTTPUpdateServer ready! Open http://");
DEBUG_PRINT(host);
DEBUG_PRINTLN(".local/update in your browser\n");
}


/**
///////////////////////////////////////////////////////////////////////////////// Timer Interrupt ISR ////////////////////////////////////////////////////////////////////////////////////
**/
void dimTimerISR()
{
if(zero_cross == 1)
{
for(int i = 0; i < NUM_CHANNELS; i++)
{
if(State[i] == 1)
{
if(Lvl_Counter[i] > Dimming_Lvl[i] + DELTA)
{
digitalWrite(Drive_Pin[i], LOW);
Lvl_Counter[i] = 0;
isHandled[i] = 1;

NumHandled++;
if(NumHandled == NumActiveChannels)
{
zero_cross = 0;
}
}
else if(isHandled[i] == 0)
{
Lvl_Counter[i]++;
}
}
}
}
}

/**
///////////////////////////////////////////////////////////////////////////////// Zero Crossing ISR ////////////////////////////////////////////////////////////////////////////////////
**/
void Zero_Crossing_Int()
{
if(NumActiveChannels > 0)
{
NumHandled = 0;

for(int i=0; i<NUM_CHANNELS; i++)
{
isHandled[i] = 0;
if(State[i] == 1)
{
digitalWrite(Drive_Pin[i], HIGH);
}
}
zero_cross = 1;
}
}

/**
//////////////////////////////////////////////////////////////////////////////////// TIMER SETTINGS /////////////////////////////////////////////////////////////////////////////////////
**/
void ICACHE_FLASH_ATTR timer_init(void)
{
//FRC1_SOURCE/NMI_SOURCE
hw_timer_init(FRC1_SOURCE, 1);
hw_timer_set_func(dimTimerISR);
hw_timer_arm(STEP_TIME);
}

/**
////////////////////////////////////////////////////////////////////////Connect the module to a WiFi access point////////////////////////////////////////////////////////////////////////
**/
int connectToWiFi()
{
WiFi.begin(ssid.c_str(), password.c_str());

int i=0;
while (WiFi.status() != WL_CONNECTED)
{
if (i == 30)
{
return -1;
}
delay(1000);
DEBUG_PRINT(".");
i++;
}
DEBUG_PRINTLN("");
DEBUG_PRINTLN("Connected to ");
DEBUG_PRINTLN(ssid);
DEBUG_PRINTLN("IP address: ");
DEBUG_PRINTLN(WiFi.localIP());

return 0;
}

'''
hw_timer.c

/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: hw_timer.c
*
* Description: hw_timer driver
*
* Modification history:
* 2014/5/1, v1.0 create this file.
*******************************************************************************/
//#include "c-types.h"
typedef __SIZE_TYPE__ size_t;
#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#include "hw_timer.h"


/******************************************************************************
* FunctionName : hw_timer_arm
* Description : set a trigger timer delay for this timer.
* Parameters : uint32 val :
in autoload mode
50 ~ 0x7fffff; for FRC1 source.
100 ~ 0x7fffff; for NMI source.
in non autoload mode:
10 ~ 0x7fffff;
* Returns : NONE
*******************************************************************************/
void hw_timer_arm(u32 val)
{
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, US_TO_RTC_TIMER_TICKS(val));
}

static void (* user_hw_timer_cb)(void) = NULL;
/******************************************************************************
* FunctionName : hw_timer_set_func
* Description : set the func, when trigger timer is up.
* Parameters : void (* user_hw_timer_cb_set)(void):
timer callback function,
* Returns : NONE
*******************************************************************************/
void hw_timer_set_func(void (* user_hw_timer_cb_set)(void))
{
user_hw_timer_cb = user_hw_timer_cb_set;
}

static void hw_timer_isr_cb(void)
{
if (user_hw_timer_cb != NULL) {
(*(user_hw_timer_cb))();
}
}

/******************************************************************************
* FunctionName : hw_timer_init
* Description : initilize the hardware isr timer
* Parameters :
FRC1_TIMER_SOURCE_TYPE source_type:
FRC1_SOURCE, timer use frc1 isr as isr source.
NMI_SOURCE, timer use nmi isr as isr source.
u8 req:
0, not autoload,
1, autoload mode,
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR hw_timer_init(FRC1_TIMER_SOURCE_TYPE source_type, u8 req)
{
if (req == 1) {
RTC_REG_WRITE(FRC1_CTRL_ADDRESS,
FRC1_AUTO_LOAD | DIVDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT);
} else {
RTC_REG_WRITE(FRC1_CTRL_ADDRESS,
DIVDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT);
}

if (source_type == NMI_SOURCE) {
ETS_FRC_TIMER1_NMI_INTR_ATTACH(hw_timer_isr_cb);
} else {
ETS_FRC_TIMER1_INTR_ATTACH(hw_timer_isr_cb, NULL);
}

TM1_EDGE_INT_ENABLE();
ETS_FRC1_INTR_ENABLE();
}

//-------------------------------Test Code Below--------------------------------------
/*
#if 0
void hw_test_timer_cb(void)
{
static uint16 j = 0;
j++;

if ((WDEV_NOW() - tick_now2) >= 1000000) {
static u32 idx = 1;
tick_now2 = WDEV_NOW();
os_printf("b%u:%d\n", idx++, j);
j = 0;
}

//hw_timer_arm(50);
}

void ICACHE_FLASH_ATTR user_init(void)
{
hw_timer_init(FRC1_SOURCE, 1);
hw_timer_set_func(hw_test_timer_cb);
hw_timer_arm(100);
}
#endif
*/

/*
NOTE:
1 if use nmi source, for autoload timer , the timer setting val can't be less than 100.
2 if use nmi source, this timer has highest priority, can interrupt other isr.
3 if use frc1 source, this timer can't interrupt other isr.

*/
'''
hw_timer.c

#ifndef HW_TIMER_H
#define HW_TIMER_H

#ifdef __cplusplus
extern "C" {
#endif

#define US_TO_RTC_TIMER_TICKS(t) \
((t) ? \
(((t) > 0x35A) ? \
(((t)>>2) * ((APB_CLK_FREQ>>4)/250000) + ((t)&0x3) * ((APB_CLK_FREQ>>4)/1000000)) : \
(((t) *(APB_CLK_FREQ>>4)) / 1000000)) : \
0)

#define FRC1_ENABLE_TIMER BIT7
#define FRC1_AUTO_LOAD BIT6

//TIMER PREDIVED MODE
typedef enum {
DIVDED_BY_1 = 0, //timer clock
DIVDED_BY_16 = 4, //divided by 16
DIVDED_BY_256 = 8, //divided by 256
} TIMER_PREDIVED_MODE;

typedef enum { //timer interrupt mode
TM_LEVEL_INT = 1, // level interrupt
TM_EDGE_INT = 0, //edge interrupt
} TIMER_INT_MODE;

typedef enum {
FRC1_SOURCE = 0,
NMI_SOURCE = 1,
} FRC1_TIMER_SOURCE_TYPE;


void hw_timer_arm(u32 val);
void hw_timer_set_func(void (* user_hw_timer_cb_set)(void));
void hw_timer_init(FRC1_TIMER_SOURCE_TYPE source_type, u8 req);
//void ICACHE_RAM_ATTR blink_gpio(void);
//volatile bool state;



#ifdef __cplusplus
}
#endif

#endif /* HW_TIMER_H */

'''

Re: NodeMCU Wireless Dimmer Webpage

PostPosted: Thu Jun 10, 2021 3:04 pm
by btidey
When you include code then put it inside code tags so that formatting is preserved. It is much more difficult to read when formatting is lost.

Having said that, it looks like this code accepts text commands sent over websockets. The server is not set up to respond to web page requests.

If you want be able to control things from a browser then you need to first add code to respond to web page requests with a response that has a web page with controls on it. Then you need to add responses to GET or POST requests that signal the actions you want performed. There are lots of examples available that show the basic principles. A starter is the Postserver example under the ESP8266WebServer library.

Re: NodeMCU Wireless Dimmer Webpage

PostPosted: Sat Aug 07, 2021 3:06 am
by a8ngus
Hi . I have put together AP Web Server for AC dimming that is not so cumbersome . You can find it here ->

https://github.com/RobotDynOfficial/RBDDimmer/issues/45