Smart Home Automation Forum

Full Version: Tuya adapter V2 arduino source code - RS485 1 phase AC Energy Meter
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
let your own RS485 AC energy meter work with Tuya app, so that can remote monitor meter data by Tuya app via internet.
[attachment=5204]
[attachment=5206]
[attachment=5207]
[attachment=5194]
arduino source code donwload:  [attachment=5195]
Code:
#include <ModbusMaster.h>
#include <Arduino.h>
#include <TuyaWifi.h>
#include "HardwareSerial.h"
//---------RS485 setting
#define DEBUG   1

#define SERIAL_BAUD   9600
#define RX_PIN    32
#define TX_PIN    33
#define SERIAL_NUM  2
#define SLAVE_ADDR  225
//#define READ_ADDR  0
#define READ_NUM   2 

uint8_t raw_vcp_data[8] = {0};
uint16_t total_energy = 0;

uint16_t READ_ADDR = 0;
const static uint16_t addr_start_arr[6] = {
  0,100,106,118,142,144,
};
const static String emeter_name_arr[6] = {
  "Total active energy",
  "Voltage",
  "Current",
  "Active power",
  "Power factor",
  "Grid frequency",
};

typedef struct
{
  float total_active_energy;
  float voltage;
  float current;
  float active_power;
  float power_factor;
  float grid_freq;
}EMETER_STR;
typedef union
{
  EMETER_STR emeter_str;
  float emeter_arr[6];
}EMETER_UNION;

/* Current device DP values */
EMETER_UNION emeter_union = {0};

HardwareSerial My485Serial(SERIAL_NUM);
ModbusMaster node;
uint16_t rcv_buf[READ_NUM] = {0};
uint16_t conv_buf[READ_NUM] = {0};

static int16_t cnt_read = 0;

static void ReadEmeterRegs(void)
{
  uint32_t read_tmp = 0;
 
  READ_ADDR = addr_start_arr[cnt_read];
  uint8_t result = node.readHoldingRegisters(READ_ADDR, READ_NUM);
  if (result == node.ku8MBSuccess) {//if communicate successful then
       
    for (uint8_t j = 0; j < READ_NUM; j++)
    {
      rcv_buf[j] = node.getResponseBuffer(j);     
    }
    conv_buf[1] = rcv_buf[0];
    conv_buf[0] = rcv_buf[1];
    emeter_union.emeter_arr[cnt_read] = *(float*)&conv_buf[0];
    switch(cnt_read)
    {
      case 0:total_energy = emeter_union.emeter_arr[cnt_read] * 10;break;
      case 1:
        read_tmp = emeter_union.emeter_arr[cnt_read] * 10;
        raw_vcp_data[0] = (read_tmp &0xff00)>>8;
        raw_vcp_data[1] = (read_tmp &0x0ff);
        break;
      case 2:
        read_tmp = emeter_union.emeter_arr[cnt_read] * 1000;
        raw_vcp_data[2] = (read_tmp &0x0ff0000)>>16;
        raw_vcp_data[3] = (read_tmp &0x0ff00)>>8;
        raw_vcp_data[4] = read_tmp &0x0ff;
        break;
      case 3:
        read_tmp = emeter_union.emeter_arr[cnt_read] * 1000;
        raw_vcp_data[5] = (read_tmp &0x0ff0000)>>16;
        raw_vcp_data[6] = (read_tmp &0x0ff00)>>8;
        raw_vcp_data[7] = read_tmp &0x0ff;
        break;
      default:break;
    }
    #if DEBUG
    Serial1.print(emeter_name_arr[cnt_read]);
    Serial1.print(":<HEX 0x");
    Serial1.print(rcv_buf[0],HEX);
    Serial1.print(" ");
    Serial1.print(rcv_buf[1],HEX);
    Serial1.print(" FVALUE ");
    Serial1.print(emeter_union.emeter_arr[cnt_read]);
    Serial1.println("> ");
    #endif
    cnt_read++;
    if(cnt_read>=4) cnt_read = 0;
  }
  else
  {
    node.clearResponseBuffer();
  }
}

//---RS485 setting end----

TuyaWifi my_device;



/* Current LED status */
unsigned char led_state = 0;
/* Connect network button pin */
int key_pin = 25;


/* Data point define */
typedef enum
{
  DPID_TOTAL_ENERGY = 1,
  //DPID_VOLTAGE,
  //DPID_CURRENT,
  //DPID_ACTIVE_POWER,
  DPID_VCP = 6,
  //DPID_POWER_FACTOR,
  //DPID_GRID_FREQ,
}EMETER_DPID_DEF;


#define LED_WiFi  26
//#define LED_User  33



/* Stores all DPs and their types. PS: array[][0]:dpid, array[][1]:dp type.
*                                     dp type(TuyaDefs.h) : DP_TYPE_RAW, DP_TYPE_BOOL, DP_TYPE_VALUE, DP_TYPE_STRING, DP_TYPE_ENUM, DP_TYPE_BITMAP
*/
unsigned char dp_array[][2] =
{
  {DPID_TOTAL_ENERGY, DP_TYPE_VALUE},
  {DPID_VCP, DP_TYPE_RAW},
};

unsigned char pid[] = {"gl3gvyksva54unam"}; ////change pid here....
unsigned char mcu_ver[] = {"1.0.0"};

/* last time */
unsigned long last_time = 0;

void setup()
{

  My485Serial.begin(SERIAL_BAUD, SERIAL_8E1, RX_PIN, TX_PIN); //RS485 serial port
  node.begin(SLAVE_ADDR,My485Serial);
  Serial.begin(9600,SERIAL_8N1,22,19);  //Tuya module serial port
  Serial1.begin(115200,SERIAL_8N1,3,1);   //USB serial port

 
  // Serial with tuyawifi
 
 

  //Initialize led port, turn off led.
  pinMode(LED_WiFi, OUTPUT);
  digitalWrite(LED_WiFi, LOW);

/*  pinMode(LED_User, OUTPUT);
  digitalWrite(LED_User, LOW);*/

  //Initialize networking keys.
  pinMode(key_pin, INPUT_PULLUP);

  //Enter the PID and MCU software version
  my_device.init(pid, mcu_ver);
  //incoming all DPs and their types array, DP numbers
  my_device.set_dp_cmd_total(dp_array, 2);
  //register DP download processing callback function
  my_device.dp_process_func_register(dp_process);
  //register upload all DP callback function
  my_device.dp_update_all_func_register(dp_update_all);
 
  //delay(300);
  last_time = millis();
}

void loop()
{
  ReadEmeterRegs();  // read RS485 sensor
  my_device.uart_service();

  //Enter the connection network mode when Pin7 is pressed.
  if (digitalRead(key_pin) == LOW) {
    delay(80);
    if (digitalRead(key_pin) == LOW) {
      my_device.mcu_set_wifi_mode(SMART_CONFIG);
    }
  }
  /* LED blinks when network is being connected */
  if ((my_device.mcu_get_wifi_work_state() != WIFI_LOW_POWER) && (my_device.mcu_get_wifi_work_state() != WIFI_CONN_CLOUD) && (my_device.mcu_get_wifi_work_state() != WIFI_SATE_UNKNOW)) {
    if (millis()- last_time >= 500) {
      last_time = millis();

      if (led_state == LOW) {
        led_state = HIGH;
      } else {
        led_state = LOW;
      }
      digitalWrite(LED_WiFi, led_state);
    }
  }

  /* report the temperature and humidity */
  if ((my_device.mcu_get_wifi_work_state() == WIFI_CONNECTED) ||
      (my_device.mcu_get_wifi_work_state() == WIFI_CONN_CLOUD)) {
    dp_update_all();
  }

  delay(1000);
}

/**
* @description: DP download callback function.
* @param {unsigned char} dpid
* @param {const unsigned char} value
* @param {unsigned short} length
* @return {unsigned char}
*/
unsigned char dp_process(unsigned char dpid,const unsigned char value[], unsigned short length)
{
  /* all DP only report */
  return TY_SUCCESS;
}

/**
* @description: Upload all DP status of the current device.
* @param {*}
* @return {*}
*/
void dp_update_all(void)
{
  my_device.mcu_dp_update((unsigned char)DPID_TOTAL_ENERGY, total_energy, 1);
  my_device.mcu_dp_update((unsigned char)DPID_VCP, raw_vcp_data, 8);
}
[attachment=5196]
[attachment=5197]
[attachment=5198]
[attachment=5199]
[attachment=5200]
[attachment=5201]
[attachment=5202]
[attachment=5203]