BMS s komunikací RS485/232/Modbus

LiFePO4, LiFeYPO4, atd., zkušenosti, rady, tipy ...
Uživatelský avatar
Marcus81
Příspěvky: 374
Registrován: pát dub 28, 2017 8:05 pm
Lokalita: Senec
Systémové napětí: 48V
Výkon panelů [Wp]: cca 16kWp
Kapacita baterie [kWh]: 30kW Pb
Bydliště: Blízko Senec, SVK

Re: BMS s komunikací RS485/232/Modbus

Příspěvek od Marcus81 »

Nikto mi tu nevie s tym poradit?
Je mozne na bms 16s pripojit napr. iba 4s?
Hybrid, 4x260Wp Amerisolar, 6x260Wp Mono CSun, 2x260Wp Aleo, 9x 230Wp JuliSolar, 32x Astronergy 245Wp, 3f-Victron Energy Multiplus 48/5000, 750 Ah trakčná, 800 Ah OPzV stacionarne, 3xMPPT Victron Energy 150/70-Tr, 1xMPPT Victron Energy 150/45-Tr, AC-out Coupling Fronius Symo 4.5-3-M
zatial vsetko vo výstavbe...
FRSO
Příspěvky: 2390
Registrován: ned srp 14, 2011 10:13 pm
Lokalita: poblíž Hodonína
Systémové napětí: >48V
Výkon panelů [Wp]: 7200
Kapacita baterie [kWh]: 9

Re: BMS s komunikací RS485/232/Modbus

Příspěvek od FRSO »

Marcus81 píše:Nikto mi tu nevie s tym poradit?
Je mozne na bms 16s pripojit napr. iba 4s?
Dle mě určitě ne, nevím o tom, zeptej se ještě mikela na fóru.
5,4 kWp JJZ 4deg,1,8kWp JV 24deg, do 13.8.2022 bylo 3,6 kWp, MPII 5k, Victron MPPT 250/85-TR, aku 9,45 kWh Lion 15S, BMS 200A, Smart Shunt 500A.
k 28.9.2024 11500kWh
Uživatelský avatar
Lui
Příspěvky: 1243
Registrován: pon srp 08, 2011 3:14 pm
Lokalita: Senec
Systémové napětí: 48V
Výkon panelů [Wp]: cca 35kwp
Kapacita baterie [kWh]: malá
Bydliště: Slovensko

Re: BMS s komunikací RS485/232/Modbus

Příspěvek od Lui »

Marcus81 píše:Nikto mi tu nevie s tym poradit?
Je mozne na bms 16s pripojit napr. iba 4s?
večšinou každý výrobca udáva na aký počet článkov má BMS,tie čo napríklad ja používam fungujú 8-16S ak by som potreboval inú možnú kombináciu článkov,tak si vyberiem nejakú inú...je trebars aj 8-24S alebo aj 10-32S iné kombinácie nepoznám,kedže v mojom systéme som neriešil nikdy,kedže to nie je pre mňa potrebné...
málo kwp ::pv:: , 60V 1,2kAh , 15S 600P Lion *batt* + 60V 198Ah Lifepo4 *batt* , 10 x MPPT VT-80 , 4xStuder XTH 8000 vo výstavbe ,
Záloha:180Wp ::pv:: ,12V LiFePO4 60Ah *batt* , epsolar 10 ,victron 350w sinus
Joskob
Příspěvky: 596
Registrován: ned kvě 12, 2019 9:56 pm
Lokalita: Poprad
Systémové napětí: 24V
Výkon panelů [Wp]: 5210
Kapacita baterie [kWh]: 24
Bydliště: Poprad

Re: BMS s komunikací RS485/232/Modbus

Příspěvek od Joskob »

Marcus81 píše:Nikto mi tu nevie s tym poradit?
Je mozne na bms 16s pripojit napr. iba 4s?
Mam 7S bms od cinana z lithiumbatterypcb a da sa nastavit od 1S az po 10S. Taktiez bms Mgod (vyzera ako nejaky klon Daly bms)
9x Solar frontier 70W ; 16x Trinasolar TSM-235PC05 235W ; 5x Moser Baer 222W (5210Wp)
Epsolar LS3024b,LS2024b,Xtra3210,Tracer3215 ; 2x smart BMS 30A ; DalyBMS 150A
Easun PWM 3000w 24/230 sinus ; Soluowill NP1200-24/230 sinus
7S120P Li-ion 18650 210+Ah ; 7S CATL 100Ah ; 7S CATL 2x 150Ah ; 8S Lifepo 305Ah (24kWh)
Uživatelský avatar
ViktorEX
Příspěvky: 416
Registrován: stř zář 16, 2020 5:45 pm

Re: BMS s komunikací RS485/232/Modbus

Příspěvek od ViktorEX »

marsal64 píše:
ViktorEX píše:hmm, hezky ... ale dal mi to nepomohlo... nemate prosim nekdo nejaky vzorovy programek?
Tak je to ten Foxtrot, třeba trochu pomůže pro inspiraci.

Kód: Vybrat vše

VAR_GLOBAL
  NUM_DALYS : USINT := 2;  // number of Dalys present
  CH_DALYS : UINT := CH3_UNI;  // UNI channel for the communication
  DALYADDR : ARRAY[1..3] of BYTE := [16#40, 16#41, 0];  // Daly addresses
  Timeout_recv_Daly : TIME := T#100MS;        // How long wait for Daly response
  CurrentBatSum : Real;   // sum of battery current from all BMS
  CurrentBatSum_cl : CL;   // color of battery current from all BMS: > 0.5 green; < -0.5 orange; else green

END_VAR


// Structure for receiving and storing raw Daly data
TYPE
  DALYBMSDATA : STRUCT

    LastError_text : STRING;
    LastError_datetime : DT;
    ErrorCount : USINT;
    LastReceive_datetime : DT;
    ReceiveOKCount : USINT;  // counter of correct communications
    maxvoltage : REAL; // maximum cell voltage
    minvoltage : REAL; // minimum cell voltage
    totvoltage : REAL; // total battery voltage "pressure"
    current : REAL; // proud
    SOC : REAL; // SOC
    minVcellNo: USINT;  // cell no with minimum voltage
    maxVcellNo: USINT;  // cell no with maximum voltage
    temperature : INT; // temperatureplota
    state : USINT; // 0 - static  1 - charge   2 - discharge
    statea : CL; // rgb
    balancing : string[4];   // 16 battery cells in pack expected here
    MOScharging : USINT; // 1 - MOS for charging on
    MOSLoad : USINT;   // 1 - MOS for discharging on
    faultstatus1 : string[8];  // bits indicating error
    faultstatus2 : string[8];  // bits indicating error 2
  END_STRUCT
END_TYPE

// Daly values store
VAR_GLOBAL RETAIN
  dalys : ARRAY[1..3] OF DALYBMSDATA;
  daly_diffvoltage_1 : real; // difference of voltage between min and max for battery 1
  daly_diffvoltage_2 : real; // difference of voltage between min and max for battery 2
END_VAR

Kód: Vybrat vše

// Communicate with Daly BMS

// Expected RS-485, all Dalys to use a single communication channel


// function to calculate checksum
FUNCTION bchksm : USINT
  VAR_INPUT
    cfrom : PTR_TO USINT; // USINT pointer to start from
    numbytes : UINT; // number of bytes
  END_VAR
  VAR
    a : USINT;
  END_VAR

  REPEAT
    a := a + cfrom^;
    cfrom := cfrom + 1;
    numbytes := numbytes - 1;
  UNTIL numbytes = 0 END_REPEAT;
  bchksm := a;
END_FUNCTION

// Structure for received message
TYPE
  Dalyrecv : STRUCT
    error : STRING[250]; // error found, '' if none
    status : USINT; // processing status: 0: ready, 1: sending, 2: receiving, 3: result ready, 4: error
    lenmesrec : UINT; // length of the raw received message
    datarec : STRING[13]; // raw content of the received message
  END_STRUCT
END_TYPE


// send and receive one message from/to Daly
FUNCTION_BLOCK fbDalySendRec1
  VAR_INPUT
    init : BOOL; // trigger to start processing
    dst_addr : BYTE;    // address of Daly to send data to
    data_id : BYTE;   // command id
  END_VAR
  VAR_OUTPUT
    rm : Dalyrecv; // Daly status and data structure
  END_VAR
  VAR
    m : STRING[13]; // message data to send
    r : STRING[13]; // message data received
    pb : PTR_TO BYTE;
    pd : PTR_TO DWORD;
    // helpers
    chs : USINT;
    SendToDaly : fbSendTo;
    RecvFromDaly : fbRecvFrom;
    recvTimer : TON; // receiving timer
  END_VAR

  // init and send the message?
  IF init THEN
    recvTimer(IN := False, PT := Timeout_Recv_Daly);

    // construct the message to be sent
    rm.error := ''; // expect no error
    pb := adr(m); // to initial byte
    pb^ := 16#A5;
    pb := pb + 1; // to communication module address
    pb^ := dst_addr;
    //pb^ := SHL(dst_addr, 4);
    pb := pb + 1; // to data id
    pb^ := data_id;
    pb := pb + 1; // to data legth
    pb^ := 8;
    // may process data to send here, if any
    pd := pb + 1; // to first data DWORD
    pd^ := 0;
    pd := pd + 4; // to second data DWORD
    pd^ := 0;
    pb := pd + 4; // to checksum
    pb^ := USINT_TO_BYTE(bchksm(adr(m), 12));

    // send
    SendToDaly(rq :=True, chanCode := CH_DALYS, lenTx := 13, data := void(m));

    // initiate receiving timer
    recvTimer(IN := True);
    
    rm.status := 2; // receiving
  END_IF;

  // exit if the main program did not processed the response (3 = response data, 4 = error), then return without further processing
  IF rm.status > 2 THEN
    RETURN;
  END_IF;

  // initiate message receive if status = 2
  RecvFromDaly(rq :=True, chanCode := CH_DALYS, lenRx := 13, data := void(r));

  // message not received?
  IF not RecvFromDaly.mesRec THEN
    // timeout?
    IF recvTimer.Q THEN
      rm.error := 'General receive error: response timeout';
      rm.status := 4; // present the error
      return;
    ELSE
      return; // message not received and no timeout - continue waiting for response
    END_IF;
  ELSE // message received

    // message received - check general error
    IF RecvFromDaly.error <> 0 THEN
      rm.error := concat('General receive error: ', GetLastComErrTxt(RecvFromDaly.error));
      rm.status := 4; // indicate the error
      return;
    END_IF;
    // no error, start parsing
    rm.lenmesrec := RecvFromDaly.lenData;
    // despite potenital error, copy the received data to the output variable, if not too long
    IF rm.lenmesrec <= 13 THEN
      Memcpy(length := rm.lenmesrec, source := void(r), dest := void(rm.datarec));
    END_IF;
    pb := adr(rm.datarec); // to start_byte
    // check start byte
    IF not pb^ = 16#a5 THEN
      // first byte is not A5
      rm.error := 'Daly receive error: the first byte is not A5';
      rm.status := 4; // indicate the error
      return;
    END_IF;
    // verify checksum
    pb := pb + 12;
    chs := BYTE_TO_USINT(pb^);
    IF chs <> bchksm(adr(rm.datarec), 12) THEN
      rm.error := 'Daly receive error: checksum verification failed';
      rm.status := 4; // indicate the error
      return;
    ELSE
      // indicate correctly received data
      rm.status := 3;
    END_IF;
  END_IF;
END_FUNCTION_BLOCK


PROGRAM DalyBMS
  VAR
    a : fbDalySendRec1; // function block to send one message to Studer and receive response
    s : Dalyrecv; // structure with receive data
    tinit : BOOL := True; // for the first run, lanuch
    pw : PTR_TO WORD;
    pb : PTR_TO BYTE;
    pd : PTR_TO DWORD;
    daly_id : USINT := 1;           //current Daly to process
    daly_addr : BYTE ;               // current Daly address
    COMMAND_MIN : USINT := 16#90;    // minimum no of command to be sent
    COMMAND_MAX : USINT := 16#98;   // maximum no of command to be sent
    command_id : USINT := 16#90;  // work variable - current command_id
    i : USINT;
  END_VAR

  // if tinit, go to next command or next Daly
  if tinit THEN
    command_id := command_id + 1;
    if command_id > COMMAND_MAX THEN
       // first command id
       command_id := COMMAND_MIN;
       // next daly
       daly_id := daly_id + 1;
       if daly_id > NUM_DALYS THEN daly_id := 1; END_IF;
    end_if;
  END_IF;

  // take daly address
  daly_addr := DALYADDR[daly_id];

  // process the current command for the current Daly
  a(init := tinit, dst_addr := daly_addr, data_id := USINT_TO_BYTE(command_id), rm => s);
  tinit := False; // synchronous - wait for response

    // verify if response or came and process
  CASE s.status OF
    2:
       RETURN;

    4 :
      // mark error to the Daly data
      dalys[daly_id].LastError_text  := s.error;
      dalys[daly_id].LastError_datetime  := GetDateTime();
      dalys[daly_id].ErrorCount  := dalys[daly_id].ErrorCount + 1;
      tinit := True;

    3 :
      // mark last received data to Daly
      dalys[daly_id].LastReceive_datetime := GetDateTime();
      dalys[daly_id].ReceiveOKCount := dalys[daly_id].ReceiveOKCount + 1;
      tinit := True;
      
      // parse - go to the first data byte
      pw := adr(s.datarec) + 4;
      pb := pw;
      pd := pw;

      case command_id of

      16#90:
         dalys[daly_id].totvoltage := int_to_real(int_to_int(word_to_int(pw^))) * 0.1;
         pw := pw + 4;
         dalys[daly_id].current := - (int_to_real(int_to_int(word_to_int(pw^))) - 30000) * 0.1; // A
         pw := pw + 2;
         dalys[daly_id].SOC := int_to_real(int_to_int(word_to_int(pw^))) * 0.1; // perc.

      16#91:
         dalys[daly_id].maxvoltage := int_to_real(int_to_int(word_to_int(pw^))) / 1000; // mV
         pb := pw + 2;
         dalys[daly_id].maxVcellNo := byte_to_usint(pb^);
         pw := pw + 3;
         dalys[daly_id].minvoltage := int_to_real(int_to_int(word_to_int(pw^))) / 1000;
         pb := pb + 3;
         dalys[daly_id].minVcellNo := byte_to_usint(pb^);
      16#92:
         dalys[daly_id].temperature := byte_to_int(pb^) - 40;  // only one thermometer expected here
      16#93:
         dalys[daly_id].state := byte_to_usint(pb^);  // 0 - static  1 - charge   2 - discharge

         case dalys[daly_id].state of
         // static - grey
         0: dalys[daly_id].statea.r := 212;
            dalys[daly_id].statea.g := 212;
            dalys[daly_id].statea.b := 212;

         // charge - green
         1: dalys[daly_id].statea.r := 0;
            dalys[daly_id].statea.g := 200;
            dalys[daly_id].statea.b := 0;

         // discharge - orange
         2: dalys[daly_id].statea.r := 255;
            dalys[daly_id].statea.g := 128;
            dalys[daly_id].statea.b := 0;
         end_case;

         pb := pb + 1;
         dalys[daly_id].MosCharging := byte_to_usint(pb^);
         pb := pb + 1;
         dalys[daly_id].MosLoad := byte_to_usint(pb^);
         
         // force switch to nearest processed command
         // switches also 95 and 96 which could not be processes in this program
         
         command_id := 16#96;  // will be incremented
         
      16#97:
         dalys[daly_id].balancing := word_to_stringf(pw^, '%04X');         // bit = the cell is balancing
      16#98:
         dalys[daly_id].faultstatus1 := dword_to_stringf(pd^,'%08X');
         pd := pd + 4;
         dalys[daly_id].faultstatus2 := dword_to_stringf(pd^,'%08X');
      END_CASE;

  END_CASE;


  // calculate total current from batteries
  CurrentBatSum := 0;
  
  for i := 1 to NUM_DALYS DO
    CurrentBatSum := CurrentBatSum + dalys[i].current;
  end_for;

  if CurrentBatSum > 0.5 THEN // charge - green
    CurrentBatSum_cl.r := 0;CurrentBatSum_cl.g := 200;CurrentBatSum_cl.b := 0;
  elsif CurrentBatSum < -0.5 THEN // discharge - orange
     CurrentBatSum_cl.r := 255;CurrentBatSum_cl.g := 128;CurrentBatSum_cl.b := 0;
  else // static - grey
     CurrentBatSum_cl.r := 212;CurrentBatSum_cl.g := 212;CurrentBatSum_cl.b := 212;
  end_if;

  // actualization of the global variables
  daly_diffvoltage_1 := dalys[1].maxvoltage - dalys[1].minvoltage;
  daly_diffvoltage_2 := dalys[2].maxvoltage - dalys[2].minvoltage;
END_PROGRAM
ach jo, sotva jsem se prokousal zacatky arduina. takze stake stejne v pr... jako pred tim. :cry:
(polo) - Ostrov 13,8 kWp (bude 15 kWp, už to tu leží), 2x Mppt Epever 5kW, Batt Lifepo4 18kWh, 3x invertor 6kW (čistý sinus) .... 300K CZK bez práce, všechno nějaká čína,

14.7. -31.12.2021
21,4 kwh/den, 57% soběstačnost
Celkem spotřeba ... 3,69 MWh

1.1. -27.3.2022,
20,6 kwh/den, 57% soběstačnost
Celkem spotřeba ... 1,8 MWh
Frantisekcon
Příspěvky: 4
Registrován: čtv dub 07, 2022 11:03 am

Re: BMS s komunikací RS485/232/Modbus

Příspěvek od Frantisekcon »

Dobrý den, poradí někdo s typem bms, který bude komunikovat s goodwe? Mám dva paky 16s lifepo4 200ah a slyšel jsem že dvě bms jdou propojit komunikací mezi sebou a komunikovat protokolem třeba Pylontech. Děkuji Fanda
mpcz
Příspěvky: 86
Registrován: sob kvě 14, 2022 1:27 pm

Re: BMS s komunikací RS485/232/Modbus

Příspěvek od mpcz »

Zdravím. Tak to taky právě řeším. Potřebuji konkrétně připojit home-made baterii 48V Lifepo4 s DALY nebo jinou BMS na DEYE střídač. Chtěl bych to řešit "mezikusem" mezi BMS DALY a střídačem, který bude překládat data z DALY na řeč střídače, popř. i zpět. Z toho by vznikl univerzální překladač dat pro všechny střídače. Nejsem příznivcem továrních ledničkových baterií pro jejich uzavřenost, blbou rozšiřitelnost, cenu a také porucha článku mě úplně děsí. A ta vybíravost na kompatibilitu podstatně zužuje možnost výběru prvků a kapacit.
Rozšifrovat odchozí komunikaci DALY problém není, ale co chce DEYE, to už problém je, protože ho zatím nemám. Nemá někdo popis protokolu DEYE a byl by ochoten ho poslat? Díky, mpcz, 26oct2022
lzahradil
Site Admin
Příspěvky: 930
Registrován: ned srp 12, 2012 1:18 am
Lokalita: blízko Plzně
Systémové napětí: 48V
Výkon panelů [Wp]: 5840
Kapacita baterie [kWh]: 28
Bydliště: CZ

Re: BMS s komunikací RS485/232/Modbus

Příspěvek od lzahradil »

FVE 5,84kWp [Axpert 5048MK - LiFePO4 580Ah@48V (zatím) | 3x Axpert MSXE 2400W - NiCd 800Ah@24V]
mpcz
Příspěvky: 86
Registrován: sob kvě 14, 2022 1:27 pm

Re: BMS s komunikací RS485/232/Modbus

Příspěvek od mpcz »

Zdravím, děkuji. Hledám protokol pro DEYE 10kW. Tato tabulka je pro DEYE nebo je to jen doporučení pro všechy výrobce? Dá se spolehnout na to, že to DEYE dodržuje? Díky, mpcz, 27oct2022

  • Podobná témata
    Odpovědi
    Zobrazení
    Poslední příspěvek