Getting my new RA configured, function questions

Do you have a question on how to do something.
Ask in here.
Post Reply
AlanM
Posts: 263
Joined: Wed Jan 01, 2014 7:26 am

Getting my new RA configured, function questions

Post by AlanM »

I'm having trouble figuring out what RA functions are available to do the things I want with my new RA. I'm slowly getting basic stuff, I think, but can't figure out the light PWM dimming and what function to call. I also can't figure out the wave modes and my 4 powerheads, 2 on the relay box ports and two on a custom dimming module.

Here is my code so far. I'd like to get PWM happening with the lights like I say in the code comments. I'm also trying to make a function that lets me set the sync/antisync behavior of my 4 powerheads which face each other across the tank at the front and back and also lets me set what mode they're running in, ReefCrest, NutrientTransport, etc.

Code: Select all

#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <Salinity.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <Humidity.h>
#include <DCPump.h>
#include <ReefAngel.h>

////// Place global variable code below here

// define default argument of isPercent in function prototype instead of definition, maybe an Arduino bug?
void CustomExpansion(byte id, byte channel, int percentage, boolean isPercent=true);
#define antiSyncMode 0; // pumps on alternate sides alternating in speed
#define syncMode 1; // pumps on alternate sides on at same time and flow meeting in middle
#define gyreMode 2; // pumps on opposite corners on at same time so that flow turns in a circle.  Opposite corners on at different times

////// Place global variable code above here


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    ReefAngel.Use2014Screen();  // Let's use 2014 Screen 
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port6Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = 0;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = Port3Bit;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port1Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    // Set the Overheat temperature setting
    InternalMemory.OverheatTemp_write( 830 );

    // Feeeding and Water Change mode speed
    ReefAngel.DCPump.FeedingSpeed=0;
    ReefAngel.DCPump.WaterChangeSpeed=0;


    // Ports that are always on
    ReefAngel.Relay.On( Port5 );
    ReefAngel.Relay.On( Port6 );

    ////// Place additional initialization code below here
    
//Custom Port Labels
ReefAngel.CustomLabels[0]="Heater"; 
ReefAngel.CustomLabels[1]="Skimmer"; 
ReefAngel.CustomLabels[2]="LEDPower"; 
ReefAngel.CustomLabels[3]="Fuge Light"; 
ReefAngel.CustomLabels[4]="Reeflo Return"; 
ReefAngel.CustomLabels[5]="PowerHeads"; 
ReefAngel.CustomLabels[6]="Alkdoser"; 
ReefAngel.CustomLabels[7]="Caldoser";  


    ////// Place additional initialization code above here
}
/*

Want to use one float valve port for skimmate locker

Relay Ports:
1 = Heater
2 = Skimmer
3 = LEDPower
4 = Fuge Light 
5 = Reeflo Return
6 = Powerheads, 2xTunze 2xJebao
7 = Alkdoser
8 = CalDoser

DC Pumps:
Actinic: Tunze Left
Daylight: Tunze Right

CustomDimmer: // Want lights with sinusoidal ramp up and down with center at 1pm starting and ending at 7am/7pm
              // want Jebaos to operate in conjunction with Tunzes some of the time and opposite some of the time, so sometimes it will be 
              // pushing water at each other, sometimes it will be turning a gyre back and forth.
0 = Jebao Left
1 = Jebao Right
2 = Violet
3 = Royal Blue
4 = White
5 = Cool Blue
6 = Deep Red
7 = Cyan
8 = PWM fans

*/
void loop()
{
    ReefAngel.StandardHeater( Port1,785,790 ); 
    ReefAngel.Relay.DelayedOn( Port2,1 );
    ReefAngel.StandardLights( Port3,7,0,19,0 ); // led power
    ReefAngel.StandardLights( Port4,15,0,10,0 ); // fuge light
    ReefAngel.DosingPumpRepeat( Port7,0,30,50 ); // alk doser
    ReefAngel.DosingPumpRepeat( Port8,15,30,50 ); // cal doser
    ReefAngel.DCPump.UseMemory = false;
    ReefAngel.DCPump.SetMode( NutrientTransport,75,10 );
    ReefAngel.DCPump.DaylightChannel = Sync; // Tunze right
    ReefAngel.DCPump.ActinicChannel = AntiSync; // Tunze left
    ////// Place your custom code below here
    CustomExpansion(0x41,0,NutrientTransportMode(0,75,500,false),true); // Jebao Left
    CustomExpansion(0x41,1,NutrientTransportMode(0,75,500,true),true); // Jebao Right
    
    // Turn off Skimmer if Locker is full
    if(ReefAngel.HighATO.IsActive())
    {
        ReefAngel.Relay.Off(Port2);
    }
    else
    {
        ReefAngel.Relay.On(Port2);
    }
    ////// Place your custom code above here

    // This should always be the last line
    ReefAngel.Portal( "AlanM" );
    ReefAngel.ShowInterface();
}

void setPHModes(byte syncModeIn, byte waveModeIn)
{
  switch (syncModeIn) {
    case antiSyncMode:
      ReefAngel.DCPump.DaylightChannel = Sync;
      ReefAngel.DCPump.ActinicChannel = AntiSync;
      // want to add code here to also set the daylight and actinic ones to the wave function/syncmode I set here
      // custom port 0 left should be AntiSync, custom port 1 on right should be Sync and set to same wave function as DC pumps
      break;
    case syncMode:
      ReefAngel.DCPump.DaylightChannel = Sync;
      ReefAngel.DCPump.ActinicChannel - Sync;
      // want to add code here to also set the daylight and actinic ones to the wave function/syncmode I set here
      // custom port 0 on left should be Sync, custom port 1 on right should be Sync and set to same wave function as DC pumps
      break;
    case gyreMode:
      ReefAngel.DCPump.DaylightChannel = Sync;
      ReefAngel.DCPump.ActinicChannel - AntiSync;
      // want to add code here to also set the daylight and actinic ones to the wave function/syncmode I set here
      // custom port 0 on left should be Sync, custom port 1 on right should be AntiSync and set to same wave function as DC pumps
      break;
  }
}

void CustomExpansion(byte id, byte channel, int percentage, boolean isPercent)
{
  Wire.beginTransmission(id);
  Wire.write(0);
  Wire.write(0xa1);
  Wire.endTransmission();
  int newdata = 0;
  if (isPercent)
  {
    newdata=(int)(percentage*40.95);
  }
  else
  {
    newdata=percentage;
  }
  Wire.beginTransmission(id);
  Wire.write(0x8+(4*channel));
  Wire.write(newdata&0xff);
  Wire.write(newdata>>8);
  Wire.endTransmission();
}

rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Getting my new RA configured, function questions

Post by rimai »

You need to use the PWMParabola for a semi sinusoidal waveform.
Something like this:
PWMParabola (7,0,19,0,0,100,0)
Roberto.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Getting my new RA configured, function questions

Post by lnevo »

For the lights, the PWMParabola function is the one you want.

PWMParabola(7,0,19,0,0,100,0) // 07:00 - 19:00 - 0% to 100%, default 0%

You would need to use that function as the argument to your CustomExpansion function or whatever it's called. You can modify the start/stop times so you can stagger each channel and/or set the percentages as desired.

For the mode changes, since your using the DCPump class, all you need to do is change the channel configuration. You'll need to manually set the custom expansion ports to the speed you want. The mode functions take true/false to indicate if they are in sync or antisync, so you can just move the current CustomExpansion calls for the jaebo's to that function and set them accordingly in each case statement.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Getting my new RA configured, function questions

Post by lnevo »

Also, here's the same question on lighting from someone else with the 16 channel expansion. That thread may help

http://forum.reefangel.com/viewtopic.ph ... ola#p38170
AlanM
Posts: 263
Joined: Wed Jan 01, 2014 7:26 am

Re: Getting my new RA configured, function questions

Post by AlanM »

Great, will check that out. Where is the right place to go for documentation for those functions like PWMParabola and the argument list and maybe examples, etc? Is it somewhere here?
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Getting my new RA configured, function questions

Post by lnevo »

http://www.easte.net/RA/html is really the only thing or browsing other peoples code that's been posted.

For me, I just dive into the libraries directory with grep :)
AlanM
Posts: 263
Joined: Wed Jan 01, 2014 7:26 am

Re: Getting my new RA configured, function questions

Post by AlanM »

Ah, looks like most of what I need is in Globals.cpp

My browser at work wasn't showing your API stuff right. At home now I can see the search function and put in PWMParabola, for instance, to see just what it does.

So if I wanted to write my own function to do something that wasn't PWMSlope or PWMParabola would I put it in Globals.cpp or somewhere else?
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Getting my new RA configured, function questions

Post by rimai »

I would recommend just placing in your own code. Just like the CustomExpansion function.
If you think that it is an awesome function that many people would benefit from it, let us know.
We can always add to future updates to the libraries.
The reason you don't want to add stuff to the libraries itself is when there is a patch release, you would loose it.
Roberto.
AlanM
Posts: 263
Joined: Wed Jan 01, 2014 7:26 am

Re: Getting my new RA configured, function questions

Post by AlanM »

Got it. I would definitely post it up and see if we could incorporate it for others.
AlanM
Posts: 263
Joined: Wed Jan 01, 2014 7:26 am

Re: Getting my new RA configured, function questions

Post by AlanM »

What do you think of this ramp function? Should work? I intend for it to start ramping up slow using the last 180 degrees of a cosine shifted up to positive values and reach a peak value at some point, and then dim down using the first 180 degrees of a cosine shifted up to positive.

Code: Select all

byte PWMSmoothRamp(byte startHour, byte startMinute, byte endHour, byte endMinute, byte startPWM, byte endPWM, byte slopeLength, byte oldValue)
{
  LightsOverride=true;
  int current_hour = hour();
  int start = NumMins(startHour, startMinute);
  int end = NumMins(endHour, endMinute);
  if (start > end) // Start is greater than End so it is over midnight
  {
    if (current_hour < endHour) start -= 1440; // past midnight
    if (current_hour >= startHour) end += 1440; // before midnight
  }
  int current = NumMins(current_hour, minute());
  if (slopeLength > ((end-start)/2) ) slopeLength = (end-start)/2; // don't allow a slope length greater than half the total period
  if (current <= start || current >= end) 
    return oldValue; // it's before the start or after the end, return the default
  else
  { // do the slope calculation
    byte pwmDelta = endPWM - startPWM;
    byte smoothPhase;
    if ((current > (start + slopeLength)) && (current < (end - slopeLength))) 
      return endPWM; // if it's in the middle of the slope, return the high level
    else if ((current - start) < slopeLength) 
    {  // it's in the beginning slope up
      smoothPhase = constrain(map(current, start, start+slopeLength, 180, 360), 180, 360);
    }
    else if ((end - current) < slopeLength)
    { // it's in the end slope down
      smoothPhase = constrain(map(current, end-slopeLength, end, 0, 180), 0, 180);
    }
    return startPWM + (pwmDelta*(1.0+(cos(radians(smoothPhase)))/2.0));
  }
}
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Getting my new RA configured, function questions

Post by lnevo »

You can plot it out... put a smaller window of time like over 2-3 hours... You can add this to set it somewhere that you can chart...

ReefAngel.CustomVar[0]=PWMSmoothRamp(.....);

Then go to

http://forum.reefangel.com/status/chart ... &filter=c0
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Getting my new RA configured, function questions

Post by lnevo »

Oh and one thing to keep in mind the ReefAngel.CustomVar variables are bytes so they can only go to 256.

Not sure if your function is returning 0-100 or 0-4096. You can use the map function to translate it down to a byte to at least see the curve.
AlanM
Posts: 263
Joined: Wed Jan 01, 2014 7:26 am

Re: Getting my new RA configured, function questions

Post by AlanM »

I haven't actually loaded any code into the RA yet since I got it. It's still shrink-wrapped while I get the code how I want it, actually, never plugged it in yet.

I just did it like the PWMParabola (which is actually a sine peak, not a parabola) function which, I think, expects percentages. I would swap it to an integer output and change the startPWM and endPWM into ints if I wanted it to give back 4096 for 12 bit dimming module, which I probably do.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Getting my new RA configured, function questions

Post by lnevo »

We'll get it online :)
AlanM
Posts: 263
Joined: Wed Jan 01, 2014 7:26 am

Re: Getting my new RA configured, function questions

Post by AlanM »

hah, I will do that tonight. Here's my latest code, for my future reference.

I have nearly everything I am doing on my current controller in plus extras.

1) 12-bit PWM rise and dim over 3 hours for my 6 light channels and PWM fans using the CustomExpansion module
2) Shut off skimmer recirc pump if skimmate locker sensor closes
3) controls heaters
4) doses alk and calcium and stops dosing alk if pH goes above 8.4
5) Runs my 4 powerheads in permanent nutrient transport mode.

Number 5 is the one I would like to work on next with the setPHModes function. to be able to set the sync state and the wave mode state of the 4 powerheads from some kind of time commands in the loop and from the GUI.

Is the NutrientTransportMode function smart enough to know that DC pumps are not supposed to be run between 0 and 30, so if I put a min speed of 0 it will skip up to 30 percent when it needs to exceed 0?

Code: Select all

#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <Salinity.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <Humidity.h>
#include <DCPump.h>
#include <ReefAngel.h>

////// Place global variable code below here

// define default argument of isPercent in function prototype instead of definition, maybe an Arduino bug?
void CustomExpansion(byte id, byte channel, int percentage, boolean isPercent=true);
#define antiSyncMode 0; // pumps on alternate sides alternating in speed
#define syncMode 1; // pumps on alternate sides on at same time and flow meeting in middle
#define gyreMode 2; // pumps on opposite corners on at same time so that flow turns in a circle.  Opposite corners on at different times

////// Place global variable code above here


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    ReefAngel.Use2014Screen();  // Let's use 2014 Screen 
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port6Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = 0;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = Port3Bit;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port1Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    // Set the Overheat temperature setting
    InternalMemory.OverheatTemp_write( 830 );

    // Feeeding and Water Change mode speed
    ReefAngel.DCPump.FeedingSpeed=0;
    ReefAngel.DCPump.WaterChangeSpeed=0;


    // Ports that are always on
    ReefAngel.Relay.On( Port5 );
    ReefAngel.Relay.On( Port6 );

    ////// Place additional initialization code below here
    
//Custom Port Labels
ReefAngel.CustomLabels[0]="Heater"; 
ReefAngel.CustomLabels[1]="Skimmer"; 
ReefAngel.CustomLabels[2]="LEDPower"; 
ReefAngel.CustomLabels[3]="Fuge Light"; 
ReefAngel.CustomLabels[4]="Return"; 
ReefAngel.CustomLabels[5]="PowerHeads"; 
ReefAngel.CustomLabels[6]="Alkdoser"; 
ReefAngel.CustomLabels[7]="Caldoser";  


    ////// Place additional initialization code above here
}
/*

Want to use one float valve port for skimmate locker

Relay Ports:
1 = Heater
2 = Skimmer
3 = LEDPower
4 = Fuge Light 
5 = Reeflo Return
6 = Powerheads, 2xTunze 2xJebao
7 = Alkdoser
8 = CalDoser

DC Pumps:
Actinic: Tunze Left
Daylight: Tunze Right

CustomDimmer: // Want lights with sinusoidal ramp up and down with center at 1pm starting and ending at 7am/7pm
              // want Jebaos to operate in conjunction with Tunzes some of the time and opposite some of the time, so sometimes it will be 
              // pushing water at each other, sometimes it will be turning a gyre back and forth.
0 = Jebao Left
1 = Jebao Right
2 = Violet
3 = Royal Blue
4 = White
5 = Cool Blue
6 = Deep Red
7 = Cyan
8 = PWM fans

*/
void loop()
{
    ReefAngel.StandardHeater( Port1,785,790 ); 
    ReefAngel.Relay.DelayedOn( Port2,1 );
    ReefAngel.StandardLights( Port3,7,0,19,0 ); // led power
    ReefAngel.StandardLights( Port4,15,0,10,0 ); // fuge light
    if (ReefAngel.Params.PH < 840) 
    {
      ReefAngel.DosingPumpRepeat( Port7,0,30,50 ); // alk doser
    }
    else
    {
      ReefAngel.Relay.Off(Port7);  // turn it off if the pH is too high
    }
    ReefAngel.DosingPumpRepeat( Port8,15,30,50 ); // cal doser
    ReefAngel.DCPump.UseMemory = false;
    ReefAngel.DCPump.SetMode( NutrientTransport,75,10 );
    ReefAngel.DCPump.DaylightChannel = Sync; // Tunze right
    ReefAngel.DCPump.ActinicChannel = AntiSync; // Tunze left
    ////// Place your custom code below here
    CustomExpansion(0x41,0,NutrientTransportMode(0,75,500,false),true); // Jebao Left
    CustomExpansion(0x41,1,NutrientTransportMode(0,75,500,true),true); // Jebao Right
    // lights
    CustomExpansion(0x41,2,PWMSmoothRamp(13,00,22,00,0,(int)(75*40.95),180,0),false); // V, feeding value, not percent from smoothramp
    CustomExpansion(0x41,3,PWMSmoothRamp(13,30,21,30,0,(int)(75*40.95),180,0),false); // RB, feeding value, not percent from smoothramp
    CustomExpansion(0x41,4,PWMSmoothRamp(13,30,21,30,0,(int)(75*40.95),180,0),false); // W, feeding value, not percent from smoothramp
    CustomExpansion(0x41,5,PWMSmoothRamp(13,30,21,30,0,(int)(50*40.95),180,0),false); // CB, feeding value, not percent from smoothramp
    CustomExpansion(0x41,6,PWMSmoothRamp(13,30,21,30,0,(int)(50*40.95),180,0),false); // DR, feeding value, not percent from smoothramp
    CustomExpansion(0x41,7,PWMSmoothRamp(13,30,21,30,0,(int)(50*40.95),180,0),false); // Cy, feeding value, not percent from smoothramp
    // fans
    CustomExpansion(0x41,8,PWMSmoothRamp(13,00,22,00,25,75,180,0),true); // Cy, feeding value, percent from smoothramp
    
    // Turn off Skimmer if Locker is full
    if(ReefAngel.HighATO.IsActive())
    {
        ReefAngel.Relay.Off(Port2);
    }
    else
    {
        ReefAngel.Relay.On(Port2);
    }
    
    ////// Place your custom code above here

    // This should always be the last line
    ReefAngel.Portal( "AlanM" );
    ReefAngel.ShowInterface();
}

void setPHModes(byte syncModeIn, byte waveModeIn)
{
  switch (syncModeIn) {
    case 0:
      ReefAngel.DCPump.DaylightChannel = Sync;
      ReefAngel.DCPump.ActinicChannel = AntiSync;
      // want to add code here to also set the daylight and actinic ones to the wave function/syncmode I set here
      // custom port 0 left should be AntiSync, custom port 1 on right should be Sync and set to same wave function as DC pumps
      break;
    case 1:
      ReefAngel.DCPump.DaylightChannel = Sync;
      ReefAngel.DCPump.ActinicChannel - Sync;
      // want to add code here to also set the daylight and actinic ones to the wave function/syncmode I set here
      // custom port 0 on left should be Sync, custom port 1 on right should be Sync and set to same wave function as DC pumps
      break;
    case 2:
      ReefAngel.DCPump.DaylightChannel = Sync;
      ReefAngel.DCPump.ActinicChannel - AntiSync;
      // want to add code here to also set the daylight and actinic ones to the wave function/syncmode I set here
      // custom port 0 on left should be Sync, custom port 1 on right should be AntiSync and set to same wave function as DC pumps
      break;
  }
}

int PWMSmoothRamp(byte startHour, byte startMinute, byte endHour, byte endMinute, int startPWM, int endPWM, byte slopeLength, int oldValue)
{
  LightsOverride=true;
  int current_hour = hour();
  int start = NumMins(startHour, startMinute);
  int end = NumMins(endHour, endMinute);
  if (start > end) // Start is greater than End so it is over midnight
  {
    if (current_hour < endHour) start -= 1440; // past midnight
    if (current_hour >= startHour) end += 1440; // before midnight
  }
  int current = NumMins(current_hour, minute());
  if (slopeLength > ((end-start)/2) ) slopeLength = (end-start)/2; // don't allow a slope length greater than half the total period
  if (current <= start || current >= end) 
    return oldValue; // it's before the start or after the end, return the default
  else
  { // do the slope calculation
    int pwmDelta = endPWM - startPWM;
    int smoothPhase;
    if ((current > (start + slopeLength)) && (current < (end - slopeLength))) 
      return endPWM; // if it's in the middle of the slope, return the high level
    else if ((current - start) < slopeLength) 
    {  // it's in the beginning slope up
      smoothPhase = constrain(map(current, start, start+slopeLength, 180, 360), 180, 360);
    }
    else if ((end - current) < slopeLength)
    { // it's in the end slope down
      smoothPhase = constrain(map(current, end-slopeLength, end, 0, 180), 0, 180);
    }
    return startPWM + (pwmDelta*(1.0+(cos(radians(smoothPhase)))/2.0));
  }
}


void CustomExpansion(byte id, byte channel, int percentage, boolean isPercent)
{
  Wire.beginTransmission(id);
  Wire.write(0);
  Wire.write(0xa1);
  Wire.endTransmission();
  int newdata = 0;
  if (isPercent)
  {
    newdata=(int)(percentage*40.95);
  }
  else
  {
    newdata=percentage;
  }
  Wire.beginTransmission(id);
  Wire.write(0x8+(4*channel));
  Wire.write(newdata&0xff);
  Wire.write(newdata>>8);
  Wire.endTransmission();
}

Post Reply