Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Pro Mini Extender #1

Closed
happytm opened this issue Dec 30, 2018 · 44 comments
Closed

Support Pro Mini Extender #1

happytm opened this issue Dec 30, 2018 · 44 comments
Assignees
Labels
awaiting for feedback More details or tests needed enhancement New feature or request question Further information is requested

Comments

@happytm
Copy link

happytm commented Dec 30, 2018

Thank you for starting great concept. I am user of great Espeasy Software on esp8266 for long time. RPIeasy could be very useful if there is I2C bridge with arduino pro mini thereby getting rid of some limitations of RPI. Whatever RPI can not do should be done by Pro Mini.

Thanks for great start.

@enesbcs
Copy link
Owner

enesbcs commented Dec 30, 2018

Where can i find instructions about creating and programming the Pro Mini? Without a working PME, i can not start even...

@enesbcs enesbcs added the help wanted Extra attention is needed label Dec 30, 2018
@happytm
Copy link
Author

happytm commented Dec 30, 2018

Here is the sketch I use with ESPeasy

https://github.com/letscontrolit/ESPEasySlaves/tree/master/MiniProExtender

I has not been updated since long time but it works fine with esp8266 using ESPeasy software with above plugin included.

I use a custom sketch to do some extra task on Pro Mini as below.

/********************************************************************************************************************\

  • Arduino project "ESP Easy" Copyright www.esp8266.nu
  • This program is free software: you can redistribute it and/or modify it under the terms of the GNU
  • General Public License as published by the Free Software Foundation, either version 3 of the License,
  • or (at your option) any later version.
  • This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  • without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  • See the GNU General Public License for more details.
  • You received a copy of the GNU General Public License along with this program in file 'License.txt'.
  • IDE download : https://www.arduino.cc/en/Main/Software
  • ESP8266 Package : https://github.com/esp8266/Arduino
  • Source Code : https://sourceforge.net/projects/espeasy/
  • Support : http://www.esp8266.nu
  • Discussion : http://www.esp8266.nu/forum/
  • Additional information about licensing can be found at : http://www.gnu.org/licenses
    ******************************************************************************************************************/
    // This file is to be loaded onto an Arduino Pro Mini so it will act as a simple IO extender to the ESP module.
    // Communication between ESP and Arduino is using the I2C bus, so only two wires needed.
    // It is possible to run the Pro Mini on 3V3, although the 16MHz versions do not officially support this at 16MHzl
    // By working on 3.3volt you can skip levelconverters on I2C, but no guarantee that it will work stable.
    // Arduino Mini Pro uses A4 and A5 for I2C bus. ESP I2C can be configured but they are on GPIO-4 and GPIO-5 by default.

#include <Wire.h>
#include <TimerOne.h> // Avaiable from http://www.arduino.cc/playground/Code/Timer1
int triac;
int dim;
volatile int i=0; // Variable to use as a counter
volatile boolean zero_cross=0; // Boolean to store a "switch" to tell us if we have crossed zero
int triac1; // Output to Opto Triac1
int triac2; // Output to Opto Triac2
int triac3; // Output to Opto Triac3
int triac4; // Output to Opto Triac4
int triac5; // Output to Opto Triac5

//int POT_pin = A0; // Pot for testing the dimming
int LED = 13; // LED for testing
int dim1; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim2; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim3; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim4; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim5; // Dimming level (0-128) 0 = on, 128 = 0ff

int freqStep = 65; // or 78 based on power supply : This is the delay-per-brightness step in microseconds.
// It is calculated based on the frequency of your voltage supply (50Hz or 60Hz)
// and the number of brightness steps you want.
//
// The only tricky part is that the chopper circuit chops the AC wave twice per
// cycle, once on the positive half and once at the negative half. This meeans
// the chopping happens at 120Hz for a 60Hz supply or 100Hz for a 50Hz supply.

// To calculate freqStep you divide the length of one full half-wave of the power
// cycle (in microseconds) by the number of brightness steps.
//
// (1000000 uS / 120 Hz) / 128 brightness steps = 65 uS / brightness step or (1000000 uS / 100 Hz) / 128 brightness steps = 78 uS / brightness step
//
// 1000000 us / 120 Hz = 8333 uS, length of one half-wave or 100 Hz =

#define I2C_MSG_IN_SIZE 4
#define I2C_MSG_OUT_SIZE 4

#define CMD_DIGITAL_WRITE 1
#define CMD_DIGITAL_READ 2
#define CMD_ANALOG_WRITE 3
#define CMD_ANALOG_READ 4

volatile uint8_t sendBuffer[I2C_MSG_OUT_SIZE];
int ESPrms; // value to be sent over I2C to ESP

void setup()
{
Wire.begin(0x7f);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
//Serial.begin(9600);

pinMode(triac1, OUTPUT); // Set the Triac1 pin as output
pinMode(triac2, OUTPUT); // Set the Triac1 pin as output
pinMode(triac3, OUTPUT); // Set the Triac1 pin as output
pinMode(triac4, OUTPUT); // Set the Triac1 pin as output
pinMode(triac5, OUTPUT); // Set the Triac1 pin as output

pinMode(LED, OUTPUT); // Set the LED pin as output

attachInterrupt(0, zero_cross_detect, RISING); // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
Timer1.initialize(freqStep); // Initialize TimerOne library for the freq we need
Timer1.attachInterrupt(dim_check, freqStep);
// Use the TimerOne Library to attach an interrupt
// to the function we use to check to see if it is
// the right time to fire the triac. This function
// will now run every freqStep in microseconds.
}

/* ******************************************************************************************************************
This part in the loop found here: [url] https://forum.arduino.cc/index.php?topic=179541.0 [/url] tnx to dc42
constant 75.7576 depends on the sensitivity of the ACS712 module
Sensitivity Min<Typ<Max mV/A
for 30A: 64< 66< 68 mV/A > constant = 5/.066 = 75.76
for 10A: 96<100<104 mV/A > constant = 5/.1 = 50.00
for 5A: 180<185<190 mV/A > constant = 5/.185 = 27.03
*/

const int currentPin = A0; // ADC pin used for ACS712

const unsigned long sampleTime = 100000UL; // sample over 100ms, it is an exact number of cycles for both 50Hz and 60Hz mains
const unsigned long numSamples = 250L; // number of samples 400 microsecond each
const unsigned long sampleInterval = sampleTime/numSamples; // sampling interval, must be longer than then ADC conversion time
int adc_zero = 514; // relative zero of the ACS712 for me 514 was best. 511
int valueRead; // value read on ADC

void zero_cross_detect() {
zero_cross = true; // set the boolean to true to tell our dimming function that a zero cross has occured
i=0;
// since the control pin stays high, the TRIAC won't 'unlatch'
// when zero-crossing, so I need to put the pins to LOW
digitalWrite(triac1, LOW);
digitalWrite(triac2, LOW);
digitalWrite(triac3, LOW);
digitalWrite(triac4, LOW);
digitalWrite(triac5, LOW);

// writing pins is like 10 times faster if
// we write the register directly
// instead of using 'digitalWrite'

}

// Turn on the TRIAC at the appropriate time
void dim_check() {
if(zero_cross == true) {

if(i>=dim1)  {                     
  digitalWrite(triac1, HIGH);  // turn on triac1
  i=0;  // reset time step counter                         
  zero_cross = false; //reset zero cross detection
}   
                       
 if(i>=dim2) {                     
  digitalWrite(triac2, HIGH);  // turn on triac2 
  i=0;  // reset time step counter                         
  zero_cross = false; //reset zero cross detection
}   
           
   
  if(i>=dim3) {                     
  digitalWrite(triac3, HIGH);  // turn on triac3
  i=0;  // reset time step counter                         
  zero_cross = false; //reset zero cross detection
}   


 if(i>=dim4) {                     
  digitalWrite(triac4, HIGH);  // turn on triac4
  i=0;  // reset time step counter                         
  zero_cross = false; //reset zero cross detection
}   


if (i>=dim5) {                     
  digitalWrite(triac5, HIGH);  // turn on triac5
  i=0;  // reset time step counter                         
  zero_cross = false; //reset zero cross detection
}    
else {
  
  i++; // increment time step counter 

}
 
                  
}                                

}

void loop()

{

     if (triac == 4) {
        dim1 = dim / 8;
         
      }
     if (triac == 5) {
        dim2 = dim / 8; 
      }

      if (triac == 6) {
        dim3 = dim / 8; 
      }
     if (triac == 7) {
        dim4 = dim / 8; 
      }

     if (triac == 8) {
        dim5 = dim / 8; 
      }

//dim = dim / 8; // set dimmer value to global integer dim
//dim = analogRead(POT_pin) / 8; // read dimmer value from potentiometer
//analogWrite(LED, dim); // write dimmer value to the LED, for debugging

/*
Serial.print(dim);
Serial.print("dim = ");
Serial.print("triac = ");
Serial.print(triac);
Serial.print("dim1 = ");
Serial.print(dim1);

Serial.print("triac1 = ");

Serial.print(triac1);
Serial.print("dim2 = ");
Serial.print(dim2) ;
Serial.print("triac2 = ");
Serial.print(triac2);
Serial.print("dim3 = ");
Serial.print(dim3);
Serial.print("triac3 = ");
Serial.print(triac3);
Serial.print("dim4 = ");
Serial.print(dim4);
Serial.print("triac4 = ");
Serial.print(triac4);
Serial.print("ESPrms = ");
Serial.print(ESPrms);

delay(1000);
Serial.print('\n');

unsigned long currentAcc = 0;
unsigned int count = 0;
unsigned long prevMicros = micros() - sampleInterval ;

while (count < numSamples)

{
if (micros() - prevMicros >= sampleInterval)
{
long adc_raw = analogRead(currentPin) - adc_zero;
currentAcc += (unsigned long)(adc_raw * adc_raw);
++count;
prevMicros += sampleInterval;
}
}

float rms = sqrt((float)currentAcc/(float)numSamples) * (27.03 / 1024.0); // see note above for this 27.03 value
ESPrms = 1000*rms; // conversion of float Ampere into integer milliAmpere needed for I2C communication

/
}
/
****************************************************************************************************************** */

void receiveEvent(int count)
{
if (count == I2C_MSG_IN_SIZE)
{
byte cmd = Wire.read();
byte port = Wire.read();
int value = Wire.read();
value += Wire.read()*256;
switch(cmd)
{
case CMD_DIGITAL_WRITE:
pinMode(port,OUTPUT);
digitalWrite(port,value);
break;
case CMD_DIGITAL_READ:
pinMode(port,INPUT_PULLUP);
clearSendBuffer();
sendBuffer[0] = digitalRead(port);
break;
case CMD_ANALOG_WRITE:
//analogWrite(port,value);
triac=(port);
if (port == 4) triac1 = (port);
if (port == 5) triac2 = (port);
if (port == 6) triac3 = (port);
if (port == 7) triac4 = (port);
if (port == 8) triac5 = (port);
dim=(value);
//dim=dim / 8;
//if (port == 4) dim1 = (value);
// if (port == 5) dim2 = (value);
// if (port == 6) dim3 = (value);
// if (port == 7) dim4 = (value);
// if (port == 8) dim5 = (value);
break;
case CMD_ANALOG_READ:
clearSendBuffer();
if (port <= 4) valueRead = analogRead(port); // port <=4 to read analog value A0,A1,A2,A3 - A4 & A5 are I2C
if (port == 100) valueRead = ESPrms; // port is any number >4 up to 255
//if (port == 2) selector = analogRead(A2);
//if (port == 3) level = analogRead(A3);
sendBuffer[0] = valueRead & 0xff;
sendBuffer[1] = valueRead >> 8;
break;
}
}
}

void clearSendBuffer()
{
for(byte x=0; x < sizeof(sendBuffer); x++)
sendBuffer[x]=0;
}

void requestEvent()
{
Wire.write((const uint8_t*)sendBuffer,sizeof(sendBuffer));
}

@happytm
Copy link
Author

happytm commented Dec 30, 2018

As you can see I am using Pro Mini for Mains current measurement and AC dimmer control which are impossible using only RPI or ESP8266.
That is the importance of including Pro Mini. Only requirement is communication going between RPI and Pro Mini via I2C bus.

Thanks

@enesbcs enesbcs added the enhancement New feature or request label Dec 30, 2018
@enesbcs
Copy link
Owner

enesbcs commented Dec 30, 2018

I found this on ebay, according to its description it is an AT Mega328 3.3V compatible with Pro Mini, i can order this if it will be sufficient to test:
https://www.ebay.com/itm/Mini-ATMEAG328-3-3V-8Mhz-Replace-ATmega128-for-Arduino-Pro-Mini-Compatible/173360751835
Otherwise I2C is not a big deal, but the ESPEasy plugin that handles the Pro Mini looks like a little complicated to me, it will not be easy to port it. Sending commands to the Pro Mini may be implemented, but for the reverse way (from ProMini to RPIEasy) currently i have no clue how to store/display data...

@enesbcs enesbcs changed the title Great Concept Support Pro Mini Extender Dec 30, 2018
@happytm
Copy link
Author

happytm commented Dec 30, 2018

I followed user Costo's post on ESPeasy forum to understand how to read values from Pro Mini into ESPeasy. Basically he set up devices in ESPeasy on devices tab to read value from Pro Mini.Link is below

https://www.letscontrolit.com/forum/viewtopic.php?f=4&t=627&p=6385&hilit=pme#p6385

@enesbcs
Copy link
Owner

enesbcs commented Dec 31, 2018

So basically we can use Dummy devices to hold values and create one (or more) ProMini devices, in which to be given the destination task and value number(s) (max 10 row per dev?) with type (analog/digital)? I've done something similar (value rerouting) with battery value watching, which can be setted in Advanced settings. (i am using an ADS1015 for this goal now)

The "compatible" device i mentioned in the previous post is right?

@happytm
Copy link
Author

happytm commented Dec 31, 2018

Yes device you chose should work fine. For that matter any arduino device should work fine with shift register for 5V device or directly without shift register for 3.3V device. Your device is 3.3V so it should be fine by connecting directly 4 wires (3.3V, GND, SCL & SDA).To store value to dummy device you can use rules if it is implemented in your code.

@happytm
Copy link
Author

happytm commented Dec 31, 2018

You will also need FTDI adapter to upload the sketch to Pro Mini like below

https://www.ebay.com/itm/FT232RL-FTDI-Serials-Adapter-Module-Mini-Port-f-USB-to-TTL-3-3V-5-5V-BBC/142727421107?hash=item213b379cb3:g:EKMAAOSwinVZtzmB:rk:1:pf:0

Arduino Uno has this usb to serial chip built in but Pro mini does not.

I live in USA and if you need Pro Mini , FTDI adapter and some extra sensors I have I can send them to you. Please let me know.

Thanks

@enesbcs
Copy link
Owner

enesbcs commented Dec 31, 2018

Thanks, but I already have a CP2102 (for flashing Sonoff devices) i think it will work for uploading, and ordered a ProMini for testing. Itt will arrive in time.. If you want to send some other sensors which is currenty not supported, itt will be nice.. but i am living in Hungary, Europe. :)

@enesbcs enesbcs added difficulty: hard It is not an impossible task, but will take a lot of time, understand it: months. difficulty: medium Looks like it will take a while, but not impossible and removed help wanted Extra attention is needed difficulty: hard It is not an impossible task, but will take a lot of time, understand it: months. labels Jan 11, 2019
@enesbcs enesbcs self-assigned this Jan 12, 2019
@enesbcs
Copy link
Owner

enesbcs commented Jan 15, 2019

I was reading and tried to interpret the PME code. But i found a possible issue: It's default address 0x7f is outside of the valid I2C range. (0x08-0x77)
https://www.totalphase.com/support/articles/200349176-7-bit-8-bit-and-10-bit-I2C-Slave-Addressing
I doubt that RPI smbus module will handle it.

@happytm
Copy link
Author

happytm commented Jan 15, 2019

Is it not possible to define different address within the range (0x008-0x77) in PME plugin and match same newly defined address in pro mini extender code on arduino ? While searching web I found following links

https://www.raspberrypi.org/forums/viewtopic.php?t=155389
https://www.raspberrypi.org/forums/viewtopic.php?t=170958
https://oscarliang.com/raspberry-pi-arduino-connected-i2c/ (using 0x04 address)
https://www.bluetin.io/interfacing/i2c-connect-raspberry-pi-arduino/ (using 0x08 address)

@enesbcs
Copy link
Owner

enesbcs commented Jan 16, 2019

Yes, it is absolutely possible, but every PME needs to be reflashed with the recompiled sketch. :) I prefer 0x3F for the new address as this is the valid counterpart for 0x7f in 7bit.

@happytm
Copy link
Author

happytm commented Jan 17, 2019

Thank you for start on PME plugin. Can't wait to test once it is implemented.

@enesbcs
Copy link
Owner

enesbcs commented Jan 17, 2019

Experimental version added at b0ca949

@enesbcs enesbcs added awaiting for feedback More details or tests needed and removed difficulty: medium Looks like it will take a while, but not impossible labels Jan 17, 2019
@happytm
Copy link
Author

happytm commented Jan 18, 2019

I started testing this plugin and following is my feedback -

  • I tested both standard address 0x3f & non standard address 0x7f and both seems to communicate with
    pro mini so that was very good start.

  • I then attached joystick to analog pin 6 & 7 & switch part of joystick to digital pin 9 of pro mini and set up 3 different devices on device page to read value from each of 3 pins it send values but they are all same value and not different value.It should be different value for each of 3 pins. following is log -

When joystick down -

22:27:46 Event: PMEanalog6#Value=0.0
22:27:46 Event: PMEanalog7#Value=0.0
22:27:47 Event: PMEdigital9#Value=0.0

When joystick in middle -

22:27:50 Event: PMEdigital9#Value=255.0
22:27:50 Event: PMEanalog6#Value=511.0
22:27:50 Event: PMEanalog7#Value=511.0

When joystick up -

22:27:55 Event: PMEanalog6#Value=1023.0
22:27:55 Event: PMEanalog7#Value=1023.0
22:27:56 Event: PMEdigital9#Value=255.0

22:28:00 Event: Clock#Time=Thu,22:28

  • When switch pressed on joystick for few seconds -

22:31:52 Event: PMEdigital9#Value=149.0
22:31:52 Event: PMEanalog6#Value=405.0
22:31:52 Event: PMEanalog7#Value=405.0
22:31:53 Event: PMEdigital9#Value=162.0
22:31:53 Event: PMEanalog6#Value=418.0
22:31:53 Event: PMEanalog7#Value=418.0
22:31:54 Event: PMEdigital9#Value=160.0
22:31:54 Event: PMEanalog7#Value=416.0
22:31:54 Event: PMEanalog6#Value=416.0
22:31:55 Event: PMEdigital9#Value=158.0
22:31:55 Event: PMEanalog6#Value=414.0
22:31:55 Event: PMEanalog7#Value=414.0
22:31:56 Event: PMEdigital9#Value=158.0
22:31:56 Event: PMEanalog7#Value=414.0
22:31:56 Event: PMEanalog6#Value=414.0
22:31:57 Event: PMEdigital9#Value=148.0
22:31:57 Event: PMEanalog6#Value=404.0
22:31:57 Event: PMEanalog7#Value=404.0
22:31:58 Event: PMEdigital9#Value=110.0
22:31:58 Event: PMEanalog6#Value=366.0
22:31:58 Event: PMEanalog7#Value=366.0
22:31:59 Event: PMEdigital9#Value=138.0
22:31:59 Event: PMEanalog6#Value=138.0
22:31:59 Event: PMEanalog7#Value=138.0
22:32:00 Event: PMEdigital9#Value=99.0
22:32:00 Event: PMEanalog6#Value=355.0
22:32:00 Event: PMEanalog7#Value=355.0
22:32:00 Event: Clock#Time=Thu,22:32
22:32:02 Event: PMEdigital9#Value=99.0
22:32:02 Event: PMEanalog6#Value=355.0
22:32:02 Event: PMEanalog7#Value=355.0
22:32:03 Event: PMEdigital9#Value=101.0
22:32:03 Event: PMEanalog6#Value=357.0
22:32:03 Event: PMEanalog7#Value=357.0
22:32:04 Event: PMEdigital9#Value=101.0
22:32:04 Event: PMEanalog6#Value=357.0
22:32:04 Event: PMEanalog7#Value=357.0
22:32:05 Event: PMEdigital9#Value=106.0
22:32:05 Event: PMEanalog6#Value=362.0
22:32:05 Event: PMEanalog7#Value=362.0
22:32:06 Event: PMEdigital9#Value=111.0
22:32:06 Event: PMEanalog6#Value=367.0
22:32:06 Event: PMEanalog7#Value=367.0
22:32:07 Event: PMEdigital9#Value=120.0
22:32:07 Event: PMEanalog6#Value=376.0
22:32:07 Event: PMEanalog7#Value=376.0
22:32:08 Event: PMEdigital9#Value=120.0
22:32:08 Event: PMEanalog6#Value=376.0
22:32:08 Event: PMEanalog7#Value=376.0
22:32:09 Event: PMEdigital9#Value=120.0
22:32:09 Event: PMEanalog6#Value=376.0
22:32:09 Event: PMEanalog7#Value=376.0
22:32:10 Event: PMEdigital9#Value=127.0
22:32:10 Event: PMEanalog6#Value=383.0
22:32:10 Event: PMEanalog7#Value=383.0
22:32:11 Event: PMEdigital9#Value=127.0
22:32:11 Event: PMEanalog6#Value=383.0
22:32:11 Event: PMEanalog7#Value=383.0
22:32:12 Event: PMEdigital9#Value=127.0
22:32:12 Event: PMEanalog6#Value=383.0
22:32:12 Event: PMEanalog7#Value=383.0
22:32:13 Event: PMEdigital9#Value=126.0
22:32:13 Event: PMEanalog6#Value=382.0
22:32:13 Event: PMEanalog7#Value=382.0
22:32:14 Event: PMEdigital9#Value=127.0
22:32:14 Event: PMEanalog6#Value=383.0
22:32:14 Event: PMEanalog7#Value=383.0
22:32:15 Event: PMEdigital9#Value=126.0
22:32:15 Event: PMEanalog6#Value=382.0
22:32:15 Event: PMEanalog7#Value=382.0
22:32:16 Event: PMEdigital9#Value=126.0
22:32:16 Event: PMEanalog6#Value=382.0
22:32:16 Event: PMEanalog7#Value=382.0
22:32:17 Event: PMEdigital9#Value=231.0
22:32:17 Event: PMEanalog6#Value=231.0
22:32:17 Event: PMEanalog7#Value=231.0

If I move joystick sideways on both ends it seems there is no effect and values in log remain same as if joystick is middle position.

For output side if at least 1 device is enabled (for reading pin value from pro mini ) then both extpwm & extgpio works fine and turn pin high or low when I issue extpwm or extgpio command from advanced tab of rpieasy. But in original espeasy there was no need to set up pme plugin on device page in order to enable extgpio and extpwm command. Output side worked automatically without setting up anything on device page for pme plugin.

It is very good start and I appreciate your efforts.

Thanks

@happytm
Copy link
Author

happytm commented Jan 18, 2019

On further testing I realised that I was using 1 second interval on device page for all 3 pins so i changed interval to 2 seconds on 2 analog pins ( analog 6 & analog 7 ) and then it works reliably as it should. For digital pin 9 on pro mini no matter what interval I set on device page it shows value of 255 but it should be 1 or 0. sorry for confusion. Is it possible to change this behavior so that when switch is pressed or released on pin 9 it send data instantly to rpi instead of waiting for 60 seconds ?

@enesbcs
Copy link
Owner

enesbcs commented Jan 18, 2019

Thanks for testing.
In RPIEasy, it will sure commands will remain at their specific plugins, so you have activate "Switch" plugin to use gpio and MCP plugin to use extgpio.. for the same reason you have to activate USBRelay plugin to use usbrelay command, and PyGame Sound Player for playaudio command, etc, etc..
The reason is simple: RPIEasy can be run on machines, that do not have GPIO support, for example i running it at my PC also with Ubuntu. And i think every plugin has it's specific task, for good reason.

I am not familiar with the Arduino side of the ProMini, pin number 9 is just forwarded as it written in the text box to the ProMini.
As i see the promini code is not capable of sending any data without receiving a read command, so i do not know, how to achieve instantous feedbacks from gpio changes. Is that function works on ESPEasy plugin? Maybe i can send several read commands per second, for ex 10 times per second. Or a new function has to be coded to the promini, that registers attachInterrupt() handler with the selected port and sends data accordingly.

@happytm
Copy link
Author

happytm commented Jan 18, 2019

Thank you for your clarification on switch plugin. I will have to test more to see if there can be something done on pro mini code.

@enesbcs
Copy link
Owner

enesbcs commented Jan 19, 2019

@happytm:
Could you try the new plugin? 7373154
Please delete PME devices, than recreate, and set Interval to 0. In this mode plugin asks the selected pin status ten times per second, and if state is changed, than event is fired. Warning: In this mode, i measured approximately +4% CPU usage/pin! So only use, if it is crucial. I tested 1 second interval with two pin and i do not found any problem, and cpu usage is minimal in this mode. (yet) With analog values it will be very noisy, for digital inputs, it could be handy.

@happytm
Copy link
Author

happytm commented Jan 20, 2019

I tried new plugin -

  • digital pin connected to switch now works instantly without any problem.
  • analog pins connected to joystick and interval set at 0 in plugin does not respond in log at all when changing joystick position. So I tried different interval from 1 second to 5 seconds and it respond with joystick activity but it shows exact same value for both.Before this commit it was working ok and showing separate values from 2 pins with 2 second interval in plugin.

@enesbcs enesbcs removed awaiting for feedback More details or tests needed enhancement New feature or request labels Jan 24, 2019
@happytm
Copy link
Author

happytm commented Jan 24, 2019

I used joystick directly because pro mini i always use is 3.3v version (8mhz) the one I sent you is 3.3v so no need to have level shifter. The programming board also is set on 3.3v via jumper. I do not populate 6 pins on edge of pro mini to program it but just use holes and hold it tight with ftdi adapter while loading the program and it works. For my tests I used analog pins A6 & A7 for joystick.

@enesbcs
Copy link
Owner

enesbcs commented Jan 24, 2019

Thanks! I rewrite the MiniProExtender sketch, relocated the slow analogread() function from the ISR into the loop, i will test it with the joystick and let you know the results.

@enesbcs
Copy link
Owner

enesbcs commented Jan 28, 2019

I think with commit e2eebc4 i reached end of the road. There are nothing more i can do with the original PME sketch, approximately 1hour of continous reading can be achieved maximum, before PME I2C receiver function fails, and only power cycling can fix it.
So i've done a boosted sketched that can be downloaded here: https://github.com/enesbcs/ESPEasySlaves/blob/master/MiniProExtender/MiniProExtender.ino
With the new sketch it is working continously for 3hours now, without error. Tested with an analog joystick (2 analog port, 1 digital, reading interval=0 all of them)

@enesbcs enesbcs added question Further information is requested awaiting for feedback More details or tests needed and removed bug Something isn't working work in progress It's currently in focus labels Jan 28, 2019
@enesbcs enesbcs removed their assignment Jan 28, 2019
@happytm
Copy link
Author

happytm commented Jan 30, 2019

Thank you for all your efforts on this plugin. I tested it last night for few hours and it was working finefor general input output control from rpieasy. I still will be using original sketch from espeasy for my project with your original plugin from few days ago that was working fine except analog read which I do not need.My project need to control 6 digital pins on promini and I am not controlling it directly but sending extpwm commands for each 6 pins of promini via rules and at pro mini I am storing it into 7 integers (1 for pin number & 6 integers for pwm values to further process in a sketch on promini without triggering pins at pro mini. like below:

case CMD_ANALOG_WRITE:
//analogWrite(port,value);
triac=(port);
if (port == 4) triac1 = (port);
if (port == 5) triac2 = (port);
if (port == 6) triac3 = (port);
if (port == 7) triac4 = (port);
if (port == 8) triac5 = (port);
if (port == 9) triac6 = (port);
dim=(value);

I tried to store values to integers from your new pro mini sketch but I was unable to do so.

At some point you can look into serial interface to pro mini instead of using I2C. I am not sure there is any code in espeasy for that.

Thanks again.

@enesbcs
Copy link
Owner

enesbcs commented Jan 30, 2019

The serial plugin is also under development, i ran some multithreading related problems with that. I will try the analog_write hacking, if analog_write worked previously than this also hast to work. But your sketch in the first post will not work in this form, than it contains a delay() in the loop section, which will effectively kill the whole I2C processing.

@happytm
Copy link
Author

happytm commented Jan 30, 2019

Oh that's a good news.
Thank you.

@enesbcs enesbcs added enhancement New feature or request work in progress It's currently in focus and removed awaiting for feedback More details or tests needed question Further information is requested labels Jan 30, 2019
@enesbcs enesbcs self-assigned this Jan 30, 2019
@enesbcs
Copy link
Owner

enesbcs commented Jan 30, 2019

Could you send the sketch you are using, without the unnecessary portions/comments? The one that you included in the first post, has some errors with comments and something is missing, as number of "}" is not ok. The section that calculates ESPrms is commented out, isn't it necessary?
This sketch is a bit cryptic to me, triac1..triac5 has no initial value as i see, but despite it, in the setup field this values used as pin numbers.. there are no way, that anything executed before setup() that assign values to them.

@enesbcs enesbcs added question Further information is requested awaiting for feedback More details or tests needed and removed work in progress It's currently in focus labels Jan 30, 2019
@happytm
Copy link
Author

happytm commented Jan 31, 2019

I am sorry I am not a programmer so I must have messed up somewhere. but following is user Costo's original sketch I am trying to use for promini:

/********************************************************************************************************************\

  • Arduino project "ESP Easy" Copyright www.esp8266.nu
  • This program is free software: you can redistribute it and/or modify it under the terms of the GNU
  • General Public License as published by the Free Software Foundation, either version 3 of the License,
  • or (at your option) any later version.
  • This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  • without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  • See the GNU General Public License for more details.
  • You received a copy of the GNU General Public License along with this program in file 'License.txt'.
  • IDE download : https://www.arduino.cc/en/Main/Software
  • ESP8266 Package : https://github.com/esp8266/Arduino
  • Source Code : https://sourceforge.net/projects/espeasy/
  • Support : http://www.esp8266.nu
  • Discussion : http://www.esp8266.nu/forum/
  • Additional information about licensing can be found at : http://www.gnu.org/licenses
    ******************************************************************************************************************/
    // This file is to be loaded onto an Arduino Pro Mini so it will act as a simple IO extender to the ESP module.
    // Communication between ESP and Arduino is using the I2C bus, so only two wires needed.
    // It is possible to run the Pro Mini on 3V3, although the 16MHz versions do not officially support this at 16MHzl
    // By working on 3.3volt you can skip levelconverters on I2C, but no guarantee that it will work stable.
    // Arduino Mini Pro uses A4 and A5 for I2C bus. ESP I2C can be configured but they are on GPIO-4 and GPIO-5 by default.

#include <Wire.h>

#define I2C_MSG_IN_SIZE 4
#define I2C_MSG_OUT_SIZE 4

#define CMD_DIGITAL_WRITE 1
#define CMD_DIGITAL_READ 2
#define CMD_ANALOG_WRITE 3
#define CMD_ANALOG_READ 4

volatile uint8_t sendBuffer[I2C_MSG_OUT_SIZE];
int ESPrms; // value to be sent over I2C to ESP

void setup()
{
Wire.begin(0x7f);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
}

/* ******************************************************************************************************************
This part in the loop found here: [url] https://forum.arduino.cc/index.php?topic=179541.0 [/url] tnx to dc42
constant 75.7576 depends on the sensitivity of the ACS712 module
Sensitivity Min<Typ<Max mV/A
for 30A: 64< 66< 68 mV/A > constant = 5/.066 = 75.76
for 10A: 96<100<104 mV/A > constant = 5/.1 = 50.00
for 5A: 180<185<190 mV/A > constant = 5/.185 = 27.03
*/

const int currentPin = A7; // ADC pin used for ACS712
const unsigned long sampleTime = 100000UL; // sample over 100ms, it is an exact number of cycles for both 50Hz and 60Hz mains
const unsigned long numSamples = 250L; // number of samples 400 microsecond each
const unsigned long sampleInterval = sampleTime/numSamples; // sampling interval, must be longer than then ADC conversion time
int adc_zero = 514; // relative zero of the ACS712 for me 514 was best. 511
int valueRead; // value read on ADC

void loop()
{
unsigned long currentAcc = 0;
unsigned int count = 0;
unsigned long prevMicros = micros() - sampleInterval ;

while (count < numSamples)
{
if (micros() - prevMicros >= sampleInterval)
{
long adc_raw = analogRead(currentPin) - adc_zero;
currentAcc += (unsigned long)(adc_raw * adc_raw);
++count;
prevMicros += sampleInterval;
}
}

float rms = sqrt((float)currentAcc/(float)numSamples) * (27.03 / 1024.0); // see note above for this 27.03 value
ESPrms = 1000rms; // conversion of float Ampere into integer milliAmpere needed for I2C communication
}
/
*******************************************************************************************************************

void receiveEvent(int count)
{
if (count == I2C_MSG_IN_SIZE)
{
byte cmd = Wire.read();
byte port = Wire.read();
int value = Wire.read();
value += Wire.read()*256;
switch(cmd)
{
case CMD_DIGITAL_WRITE:
pinMode(port,OUTPUT);
digitalWrite(port,value);
break;
case CMD_DIGITAL_READ:
pinMode(port,INPUT_PULLUP);
clearSendBuffer();
sendBuffer[0] = digitalRead(port);
break;
case CMD_ANALOG_WRITE:
analogWrite(port,value);
break;
case CMD_ANALOG_READ:
clearSendBuffer();
if (port <= 4) valueRead = analogRead(port); // port <=4 to read analog value A0,A1,A2,A3 - A4 & A5 are I2C
if (port == 100) valueRead = ESPrms; // port is any number >4 up to 255
sendBuffer[0] = valueRead & 0xff;
sendBuffer[1] = valueRead >> 8;
break;
}
}
}

void clearSendBuffer()
{
for(byte x=0; x < sizeof(sendBuffer); x++)
sendBuffer[x]=0;
}

void requestEvent()
{
Wire.write((const uint8_t*)sendBuffer,sizeof(sendBuffer));
}

Also for AC dimmers I wanted to use this original sketch which is below.I was trying to use input from RPIEasy and save it into integers at pro mini and then use those values to fire triacs. :

/*
AC Light Control

Ryan McLaughlin ryanjmclaughlin@gmail.com

The hardware consists of an Triac to act as an A/C switch and
an opto-isolator to give us a zero-crossing reference.
The software uses two interrupts to control dimming of the light.
The first is a hardware interrupt to detect the zero-cross of
the AC sine wave, the second is software based and always running
at 1/128 of the AC wave speed. After the zero-cross is detected
the function check to make sure the proper dimming level has been
reached and the light is turned on mid-wave, only providing
partial current and therefore dimming our AC load.

Thanks to http://www.andrewkilpatrick.org/blog/?page_id=445
and http://www.hoelscher-hi.de/hendrik/english/dimmer.htm
*/

/*
Modified by Mark Chester mark@chesterfamily.org

to use the AC line frequency (half-period) as a reference point
and fire the triacs based on that plus a count of dimming steps.
Tracks the line frequency and adjusts accordingly. Can set up to
an estimated 512 steps of dimmer resolution.

*/
#include <Wire.h>
#include <TimerOne.h> // http://www.arduino.cc/playground/Code/Timer1

int dim1; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim2; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim3; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim4; // Dimming level (0-128) 0 = on, 128 = 0ff
//int dim5; // Dimming level (0-128) 0 = on, 128 = 0ff

int triac1; // Output to Opto Triac1
int triac2; // Output to Opto Triac2
int triac3; // Output to Opto Triac3
int triac4; // Output to Opto Triac4
//int triac5; // Output to Opto Triac5

// General
unsigned long int ZeroXTime[4] = {0,0,0,0}; // Timestamp in micros() of the zero crossing interrupts
unsigned long int DimStep; // How many micros() in each step of dimming
unsigned long int AvgPeriod; // The average line voltage period in micros()
unsigned long int PeriodResync = 3000; // Number of milliseconds between line freq measurements
unsigned long int ResetPeriod = PeriodResync; // The timestamp in millis() when we will measure the period again
unsigned long int DimRes = 256; // How many steps of dimmer resolution
volatile unsigned long int DimStepCounter; // For counting Timer1 interrupts
volatile unsigned long int FireTriac[4] = {0,0,0,0}; // When it's OK to fire the triacs, in counts of DimRes
volatile boolean zero_cross = 0; // Tels us we've crossed the zero line
//byte TriacPin[4] = {4,5,6,7}; // Which digital IO pins to use
byte TriacPin[4] = {triac1,triac2,triac3,triac4}; // Which digital IO pins to use

#define I2C_MSG_IN_SIZE 4
#define I2C_MSG_OUT_SIZE 4

#define CMD_DIGITAL_WRITE 1
#define CMD_DIGITAL_READ 2
#define CMD_ANALOG_WRITE 3
#define CMD_ANALOG_READ 4

volatile uint8_t sendBuffer[I2C_MSG_OUT_SIZE];

void setup() { // Begin setup
Wire.begin(0x3f);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
Timer1.initialize(DimStep); // Start up the Timer1 timer
attachInterrupt(0, zero_cross_detect, FALLING); // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
pinMode(triac1, OUTPUT); // Set the Triac pin as output
pinMode(triac2, OUTPUT); // Set the Triac pin as output
pinMode(triac3, OUTPUT); // Set the Triac pin as output
pinMode(triac4, OUTPUT); // Set the Triac pin as output
measure_half_period(); // Initially measure the half period
} // End setup

void measure_half_period() {
zero_cross = 0; // Clearing this here increases the accuracy of the measurement
byte F = 0; // Frequency counter counter ;)
while ( F < 4 ) { // This loop takes 4 zero cross samples
if ( zero_cross ) { // Only run if a zero cross is detected
ZeroXTime[F] = micros(); // Set the new current zero cross time in micros()
zero_cross = 0; // Reset zero_cross
F++; // Bump the counter for the next sample
}
} // Now we calc the length of each DimStep
DimStep = (((ZeroXTime[1]-ZeroXTime[0]) + (ZeroXTime[2]-ZeroXTime[1]) + (ZeroXTime[3]-ZeroXTime[2])) / 3) / DimRes;
Timer1.attachInterrupt(fire_triacs, DimStep); // (Re)Associate fire_triacs() with the Timer1 interrupt and the latest DimStep period
ResetPeriod = ResetPeriod + PeriodResync; // Set the next time when we'll measure the half period again
}

void zero_cross_detect() { // function to be fired at the zero crossing
zero_cross = 1; // set a variable that's picked up later
DimStepCounter = 0; // Reset the step counter for the next round of triac firings
}

void fire_triacs() { // Called every DimStep (Timer1 interrupt, checks FireTriac[n] and fires if it's time
if ( FireTriac[0] == DimStepCounter ) { // Is it time to fire?
digitalWrite(triac1, HIGH); // Fire the Triac mid-phase
delayMicroseconds(2);
digitalWrite(triac1, LOW); // Turn off the Triac gate (Triac will not turn off until next zero cross)
}
if ( FireTriac[1] == DimStepCounter ) { // Is it time to fire?
digitalWrite(triac2, HIGH); // Fire the Triac mid-phase
delayMicroseconds(2);
digitalWrite(triac2, LOW); // Turn off the Triac gate (Triac will not turn off until next zero cross)
}
if ( FireTriac[2] == DimStepCounter ) { // Is it time to fire?
digitalWrite(triac3, HIGH); // Fire the Triac mid-phase
delayMicroseconds(2);
digitalWrite(triac3, LOW); // Turn off the Triac gate (Triac will not turn off until next zero cross)
}
if ( FireTriac[3] == DimStepCounter ) { // Is it time to fire?
digitalWrite(triac4, HIGH); // Fire the Triac mid-phase
delayMicroseconds(2);
digitalWrite(triac4, LOW); // Turn off the Triac gate (Triac will not turn off until next zero cross)
}
DimStepCounter++; // This counter increments every time fire_triacs runs
}

void loop() { // Main Loop
if ( millis() >= ResetPeriod ) { // Measure the half period every PeriodResync milliseconds to prevent drift
measure_half_period();
}
FireTriac[0] = (DimRes * dim1) / 1024; // Read input and calc the next triac fire time
FireTriac[1] = (DimRes * dim2) / 1024; // Read input and calc the next triac fire time
FireTriac[2] = (DimRes * dim3) / 1024; // Read input and calc the next triac fire time
FireTriac[3] = (DimRes * dim4) / 1024; // Read input and calc the next triac fire time

//FireTriac[2] = (DimRes * analogRead(2)) / 1024; // Read input and calc the next triac fire time
//FireTriac[3] = (DimRes * analogRead(3)) / 1024; // Read input and calc the next triac fire time
}

void receiveEvent(int count)
{
if (count == I2C_MSG_IN_SIZE)
{
byte cmd = Wire.read();
byte port = Wire.read();
int value = Wire.read();
value += Wire.read()*256;
switch(cmd)
{
case CMD_DIGITAL_WRITE:
pinMode(port,OUTPUT);
digitalWrite(port,value);
break;
case CMD_DIGITAL_READ:
pinMode(port,INPUT_PULLUP);
clearSendBuffer();
sendBuffer[0] = digitalRead(port);
break;
case CMD_ANALOG_WRITE:
//analogWrite(port,value);
//triac=(port);
if (port == 4) triac1 = (port);
if (port == 5) triac2 = (port);
if (port == 6) triac3 = (port);
if (port == 7) triac4 = (port);
//if (port == 8) triac5 = (port);
//dim=(value);
//dim=dim / 8;
if (port == 4) dim1 = (value);
if (port == 5) dim2 = (value);
if (port == 6) dim3 = (value);
if (port == 7) dim4 = (value);
//if (port == 8) dim5 = (value);
break;
case CMD_ANALOG_READ:
clearSendBuffer();
if (port <= 4) valueRead = analogRead(port); // port <=4 to read analog value A0,A1,A2,A3 - A4 & A5 are I2C
if (port == 100) valueRead = ESPrms; // port is any number >4 up to 255
//if (port == 2) selector = analogRead(A2);
//if (port == 3) level = analogRead(A3);
sendBuffer[0] = valueRead & 0xff;
sendBuffer[1] = valueRead >> 8;
break;
}
}
}

void clearSendBuffer()
{
for(byte x=0; x < sizeof(sendBuffer); x++)
sendBuffer[x]=0;
}

void requestEvent()
{
Wire.write((const uint8_t*)sendBuffer,sizeof(sendBuffer));
}

I also is planning to use following rules in RPIEasy Rules tab and I tested it with pro mini with your original Promini plugin and it was storing dimmer values and triac value in integers at pro mini fine.

4 AC dimmers with 8 (128 x 8 = 1024 ) dimming level control menu for Raspberry pi using apds9960 gesture sensor with pro mini extender plugin on pi and slave code on pro mini

on 9960#Gesture do
if [9960#Gesture]=10
TaskValueSet,12,1,[dimmer#pin]+1
if [dimmer#pin]>9
TaskValueSet,12,1,9 # set higher limit of GPIO pin number for 4 dimmers
if [9960#Gesture]=20
TaskValueSet,12,1,[dimmer#pin]-1
if [dimmer#pin]<6
TaskValueSet,12,1,6 # set lower limit of GPIO pin number for 4 dimmers
if [9960#Gesture]=30
TaskValueSet,12,2,[dimmer#dimvalue]-128
if [dimmer#dimvalue]<0
TaskValueSet,12,2,0 # set lower limit for pwm value
if [9960#Gesture]=40
TaskValueSet,12,2,[dimmer#dimvalue]+128
if [dimmer#dimvalue]>1000
TaskValueSet,12,2,1000 # set upper limit for pwm value
if [9960#Gesture]=50
TaskValueSet,12,2,1000 # turn on dimmer at full power
if [9960#Gesture]=60
TaskValueSet,12,2,0 # turn off dimmer
endon

on dimmer#pin do
Publish %sysname%/dimmer/pin,[dimmer#pin]

endon

on dimmer#dimvalue do
Publish %sysname%/dimmer/dimvalue,[dimmer#dimvalue]
EXTPWM,[dimmer#pin],[dimmer#dimvalue] # Send PIN and PWM value to promini (stored pwm values in 4 different integers at promini for each Pin via I2C if used with PME (pro mini extender) plugin
oledcmd,clear
oledcmd,on
oled,6,1,Fan#[dimmer#pin]=[dimmer#dimvalue]

endon

Following are rules I use for esp8266 (espeasy) device for control using MPR121 sensor:

4 channel dimmer control

on key#press=17.00 do // MPR121 up key press for dimmer 1
TaskValueSet,12,1,[dummy#d1]+127 // Set dummy sensor 1 value
if [dummy#d1]>1000
TaskValueSet,12,1,1000
endif
EXTPWM,6,[dummy#d1] // set pro mini pin 6 pwm value to dummy sensor 1 value
oled,2,4,FAN1=[dummy#d1] // Set oled line 2 & letter 4 to dummy sensor 1 value
endon

on key#press=272.00 do // MPR121 down key press for dimmer 1
TaskValueSet,12,1,[dummy#d1]-128
if [dummy#d1]<0
TaskValueSet,12,1,0
endif
EXTPWM,6,[dummy#d1]
oled,2,4,FAN1=[dummy#d1]
endon

on key#press=34.00 do
TaskValueSet,12,2,[dummy#d2]+128
if [dummy#d2]>1000
TaskValueSet,12,2,1000
endif
EXTPWM,7,[dummy#d2]
oled,2,4,FAN2=[dummy#d2]
endon

on key#press=544.00 do
TaskValueSet,12,2,[dummy#d2]-128
if [dummy#d2]<0
TaskValueSet,12,2,0
endif
EXTPWM,7,[dummy#d2]
oled,2,4,FAN2=[dummy#d2]
endon

on key#press=68.00 do
TaskValueSet,12,3,[dummy#d3]+128
if [dummy#d3]>1000
TaskValueSet,12,3,1000
endif
EXTPWM,8,[dummy#d3]
oled,2,4,FAN3=[dummy#d3]
endon

on key#press=1088.00 do
TaskValueSet,12,3,[dummy#d3]-128
if [dummy#d3]<0
TaskValueSet,12,3,0
endif
EXTPWM,8,[dummy#d3]
oled,2,4,FAN3=[dummy#d3]
endon

on key#press=136.00 do
TaskValueSet,12,4,[dummy#d4]+128
if [dummy#d4]>1000
TaskValueSet,12,4,1000
endif
EXTPWM,9,[dummy#d4]
oled,2,4,FAN4=[dummy#d4]
endon

on key#press=2176.00 do
TaskValueSet,12,4,[dummy#d4]-128
if [dummy#d4]<0
TaskValueSet,12,4,0
endif
EXTPWM,9,[dummy#d4]
oled,2,4,FAN4=[dummy#d4]
endon

on dimmer1 do // when http://192.168.0.73/control?cmd=event,dimmer1=100 command issued from browser
TaskValueSet 12,1,%eventvalue% // store pwm level value of 0 to 1023 from above command into dummy sensor
oled,2,4,FAN1=[dummy#d1]
endon

on dimmer2 do
TaskValueSet 12,2,%eventvalue%
oled,2,4,FAN2=[dummy#d2]
endon

on dimmer3 do
TaskValueSet 12,3,%eventvalue%
oled,2,4,FAN3=[dummy#d3]
endon

on dimmer4 do
TaskValueSet 12,4,%eventvalue%
oled,2,4,FAN4=[dummy#d4]
endon

I hope this is not too confusing.

Thanks.

@enesbcs
Copy link
Owner

enesbcs commented Feb 1, 2019

@happytm
Copy link
Author

happytm commented Feb 2, 2019

I tested your sketches but did not work for me so I created following sketch & used latest plugin which work perfect for me. I think finally you have resolved this issue . I watched serial console on pro mini and it is changing integer values properly. Also I was getting proper values in to rpieasy for 3 analog values from pro mini. I very much appreciate your effort. Also can you commit following sketch for future reference before I mess it up again.

/********************************************************************************************************************\

  • Arduino project "ESP Easy" Copyright www.esp8266.nu
  • This program is free software: you can redistribute it and/or modify it under the terms of the GNU
  • General Public License as published by the Free Software Foundation, either version 3 of the License,
  • or (at your option) any later version.
  • This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  • without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  • See the GNU General Public License for more details.
  • You received a copy of the GNU General Public License along with this program in file 'License.txt'.
  • IDE download : https://www.arduino.cc/en/Main/Software
  • ESP8266 Package : https://github.com/esp8266/Arduino
  • Source Code : https://sourceforge.net/projects/espeasy/
  • Support : http://www.esp8266.nu
  • Discussion : http://www.esp8266.nu/forum/
  • Additional information about licensing can be found at : http://www.gnu.org/licenses
    ******************************************************************************************************************/
    // This file is to be loaded onto an Arduino Pro Mini so it will act as a simple IO extender to the ESP module.
    // Communication between ESP and Arduino is using the I2C bus, so only two wires needed.
    // It is possible to run the Pro Mini on 3V3, although the 16MHz versions do not officially support this at 16MHzl
    // By working on 3.3volt you can skip levelconverters on I2C, but no guarantee that it will work stable.
    // Arduino Mini Pro uses A4 and A5 for I2C bus. ESP I2C can be configured but they are on GPIO-4 and GPIO-5 by default.

/*
AC Light Control

Updated by Robert Twomey rtwomey@u.washington.edu

Changed zero-crossing detection to look for RISING edge rather
than falling. (originally it was only chopping the negative half
of the AC wave form).

Also changed the dim_check() to turn on the Triac, leaving it on
until the zero_cross_detect() turn's it off.

Ryan McLaughlin ryanjmclaughlin@gmail.com

The hardware consists of an Triac to act as an A/C switch and
an opto-isolator to give us a zero-crossing reference.
The software uses two interrupts to control dimming of the light.
The first is a hardware interrupt to detect the zero-cross of
the AC sine wave, the second is software based and always running
at 1/128 of the AC wave speed. After the zero-cross is detected
the function check to make sure the proper dimming level has been
reached and the light is turned on mid-wave, only providing
partial current and therefore dimming our AC load.

Thanks to http://www.andrewkilpatrick.org/blog/?page_id=445
and http://www.hoelscher-hi.de/hendrik/english/dimmer.htm

*/
#include <Wire.h>
#include <TimerOne.h> // Avaiable from http://www.arduino.cc/playground/Code/Timer1

#define I2C_MSG_IN_SIZE 4
#define I2C_MSG_OUT_SIZE 4

#define CMD_DIGITAL_WRITE 1
#define CMD_DIGITAL_READ 2
#define CMD_ANALOG_WRITE 3
#define CMD_ANALOG_READ 4
//#define CMD_ASK_MAX_FUNC 0x10

//volatile byte I2CReceived = 0;
//volatile byte I2CDataReady = 0;
volatile uint8_t sendBuffer[I2C_MSG_OUT_SIZE];
//uint8_t EmptBuffer[I2C_MSG_OUT_SIZE];

//volatile int value = 0;
//volatile byte port = 0;
//volatile byte cmd = 0;
int ESPrms=0; // value to be sent over I2C to ESP

int triac;
int dim;

volatile int i=0; // Variable to use as a counter
volatile boolean zero_cross=0; // Boolean to store a "switch" to tell us if we have crossed zero

int triac1; // Output to Opto Triac1
int triac2; // Output to Opto Triac2
int triac3; // Output to Opto Triac3
int triac4; // Output to Opto Triac4
int triac5; // Output to Opto Triac5
int triac6; // Output to Opto Triac6

int LED = 10; // LED for testing

int dim1; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim2; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim3; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim4; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim5; // Dimming level (0-128) 0 = on, 128 = 0ff
int dim6; // Dimming level (0-128) 0 = on, 128 = 0ff

int freqStep = 65; // or 78 based on power supply : This is the delay-per-brightness step in microseconds.
// It is calculated based on the frequency of your voltage supply (50Hz or 60Hz)
// and the number of brightness steps you want.
//
// The only tricky part is that the chopper circuit chops the AC wave twice per
// cycle, once on the positive half and once at the negative half. This meeans
// the chopping happens at 120Hz for a 60Hz supply or 100Hz for a 50Hz supply.

// To calculate freqStep you divide the length of one full half-wave of the power
// cycle (in microseconds) by the number of brightness steps.
//
// (1000000 uS / 120 Hz) / 128 brightness steps = 65 uS / brightness step or (1000000 uS / 100 Hz) / 128 brightness steps = 78 uS / brightness step
//
// 1000000 us / 120 Hz = 8333 uS, length of one half-wave or 100 Hz =

void setup()
{
// for (byte x = 0; x < sizeof(sendBuffer); x++)
// sendBuffer[x] = 0;
// for (byte x = 0; x < sizeof(EmptBuffer); x++)
// EmptBuffer[x] = 0xff;
Wire.begin(0x3f);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
Serial.begin(9600);

pinMode(triac1, OUTPUT); // Set the Triac1 pin as output
pinMode(triac2, OUTPUT); // Set the Triac2 pin as output
pinMode(triac3, OUTPUT); // Set the Triac3 pin as output
pinMode(triac4, OUTPUT); // Set the Triac4 pin as output
pinMode(triac5, OUTPUT); // Set the Triac5 pin as output
pinMode(triac6, OUTPUT); // Set the Triac6 pin as output */

pinMode(LED, OUTPUT); // Set the LED pin as output

attachInterrupt(0, zero_cross_detect, RISING); // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
Timer1.initialize(freqStep); // Initialize TimerOne library for the freq we need
Timer1.attachInterrupt(dim_check, freqStep);
// Use the TimerOne Library to attach an interrupt
// to the function we use to check to see if it is
// the right time to fire the triac. This function
// will now run every freqStep in microseconds.
}

/* ******************************************************************************************************************
This part in the loop found here: [url] https://forum.arduino.cc/index.php?topic=179541.0 [/url] tnx to dc42
constant 75.7576 depends on the sensitivity of the ACS712 module
Sensitivity Min<Typ<Max mV/A
for 30A: 64< 66< 68 mV/A > constant = 5/.066 = 75.76
for 10A: 96<100<104 mV/A > constant = 5/.1 = 50.00
for 5A: 180<185<190 mV/A > constant = 5/.185 = 27.03
*/

const int currentPin = A0; // ADC pin used for ACS712
const unsigned long sampleTime = 100000UL; // sample over 100ms, it is an exact number of cycles for both 50Hz and 60Hz mains
const unsigned long numSamples = 250L; // number of samples 400 microsecond each
const unsigned long sampleInterval = sampleTime/numSamples; // sampling interval, must be longer than then ADC conversion time
int adc_zero = 514; // relative zero of the ACS712 for me 514 was best. 511
int valueRead;

void zero_cross_detect() {
zero_cross = true; // set the boolean to true to tell our dimming function that a zero cross has occured
i=0;
// since the control pin stays high, the TRIAC won't 'unlatch'
// when zero-crossing, so I need to put the pins to LOW
digitalWrite(triac1, LOW);
digitalWrite(triac2, LOW);
digitalWrite(triac3, LOW);
digitalWrite(triac4, LOW);
digitalWrite(triac5, LOW);
digitalWrite(triac6, LOW);

// writing pins is like 10 times faster if
// we write the register directly
// instead of using 'digitalWrite'

}

// Turn on the TRIAC at the appropriate time
void dim_check() {
if(zero_cross == true) {

if(i>=dim1)  {                     
  digitalWrite(triac1, HIGH);  // turn on triac1
  i=0;  // reset time step counter                         
  zero_cross = false; //reset zero cross detection
}   
                       
  if(i>=dim2) {                     
  digitalWrite(triac2, HIGH);  // turn on triac2 
  
  i=0;  // reset time step counter                         
  zero_cross = false; //reset zero cross detection
}   
           
   
  if(i>=dim3) {                     
  digitalWrite(triac3, HIGH);  // turn on triac3
  
  i=0;  // reset time step counter                         
  zero_cross = false; //reset zero cross detection
}   


 if(i>=dim4) {                     
  digitalWrite(triac4, HIGH);  // turn on triac4
  
  i=0;  // reset time step counter                         
  zero_cross = false; //reset zero cross detection
}   

if(i>=dim5) {
digitalWrite(triac5, HIGH); // turn on triac5

  i=0;  // reset time step counter                         
  zero_cross = false; //reset zero cross detection
}   

  if (i>=dim6) {                     
  digitalWrite(triac6, HIGH);  // turn on triac6
  i=0;  // reset time step counter                         
  zero_cross = false; //reset zero cross detection
}    

else {
  
  i++; // increment time step counter 

}
 
                  
}                                

}

// void handleI2C()

void loop()
{
if (triac == 4) {
dim1=dim;

      }
     if (triac == 5) {
        dim2=dim; 
      }

      if (triac == 6) {
        dim3=dim; 
      }
     if (triac == 7) {
        dim4=dim; 
      }

     if (triac == 8) {
        dim5=dim; 
      }

      if (triac == 9) {
        dim6=dim; 
      }

      dim_check();

//dim = dim / 8; // set dimmer value to global integer dim
//dim = analogRead(POT_pin) / 8; // read dimmer value from potentiometer
analogWrite(LED, dim); // write dimmer value to the LED, for debugging

Serial.print("dim = ");
Serial.print(dim);

//Serial.print("triac = ");
//Serial.print(triac);

Serial.print(" t1 = ");
Serial.print(triac1);
Serial.print(" d1 = ");
Serial.print(dim1);
Serial.print(" t2 = ");
Serial.print(triac2);
Serial.print(" d2 = ");
Serial.print(dim2);
Serial.print(" t3 = ");
Serial.print(triac3);
Serial.print(" d3 = ");
Serial.print(dim3);
Serial.print(" t4 = ");
Serial.print(triac4);
Serial.print(" d4 = ");
Serial.print(dim4);
Serial.print(" t5 = ");
Serial.print(triac5);
Serial.print(" d5 = ");
Serial.print(dim5);
Serial.print(" t6 = ");
Serial.print(triac6);
Serial.print(" d6 = ");
Serial.print(dim6);

// Serial.println(" ESPrms = ");
// Serial.print(ESPrms);

delay(10000);
Serial.print('\n');

}

void receiveEvent(int count)
{
if (count == I2C_MSG_IN_SIZE)
{
byte cmd = Wire.read();
byte port = Wire.read();
int value = Wire.read();
value += Wire.read()*256;
switch(cmd)
{
case CMD_DIGITAL_WRITE:
pinMode(port,OUTPUT);
digitalWrite(port,value);
break;
case CMD_DIGITAL_READ:
pinMode(port,INPUT_PULLUP);
clearSendBuffer();
sendBuffer[0] = digitalRead(port);
break;
case CMD_ANALOG_WRITE:
//analogWrite(port,value);
triac=(port);
dim=(value);
if (port == 4) triac1 = (port);
if (port == 5) triac2 = (port);
if (port == 6) triac3 = (port);
if (port == 7) triac4 = (port);
if (port == 8) triac5 = (port);
if (port == 9) triac6 = (port);
break;

    case CMD_ANALOG_READ:
    
    if (port <= 4) valueRead = analogRead(port); // port <=4 to read analog value A0,A1,A2,A3 - A4 & A5 are I2C
   // if (port > 79) valueRead = ESPrms; // port is any number >4 up to 255
    sendBuffer[0] = valueRead & 0xff;
    sendBuffer[1] = valueRead >> 8;
    
    break;
  }

}
}

void clearSendBuffer()
{
for(byte x=0; x < sizeof(sendBuffer); x++)
sendBuffer[x]=0;
}

void requestEvent()
{
Wire.write((const uint8_t*)sendBuffer,sizeof(sendBuffer));
}

Thank you.

@enesbcs
Copy link
Owner

enesbcs commented Feb 3, 2019

I can add it, but this sketch is using the same old I2C handling, which can lead a lockup because analogread() function located are in the receiveEvent block which is an ISR function. I am afraid that after several hour it will come about.

@enesbcs
Copy link
Owner

enesbcs commented Feb 3, 2019

Uploaded to https://github.com/enesbcs/ESPEasySlaves/tree/master/MiniProExtenderOACS
In case of further bugs, please open a new issue.

@enesbcs enesbcs closed this as completed Feb 3, 2019
enesbcs pushed a commit that referenced this issue Mar 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting for feedback More details or tests needed enhancement New feature or request question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants
@enesbcs @happytm and others