Home / PLC / Communication with Siemens S7 Plc with C# and S7.Net plc driver

Communication with Siemens S7 Plc with C# and S7.Net plc driver

In this article I explain how to implement a Siemens S7 plc driver by using the open source driver S7.Net.

You can find S7.Net sources on GitHub: https://github.com/killnine/s7netplus.

How to video

Summary

Why S7.Net: features and capabilities of the driver

S7.Net is a plc driver written in C#, this means that you don’t have to handle any interoperability with native code, but it just use OO programming and all the .Net features that you are familiar with.

Basic capabilities:
• Can connect and disconnect with the plc using sockets
• Can read and write bytes from a single area of memory, given a starting address and the number of bytes.

High level features:
• Can directly map DBs to classes and structs
• The types of C# are mapped into types of S7 and there are converters for every type (double to REAL, int to DEC, etc)
• It is easy to use, well written and perfectly readable
• It’s open source, MIT license permit you to use it in every commercial application
• Did I already say that it’s written in C#, no interop at all?

What it’s not good about S7.Net, roadmap for future upgrades:
• Lack of documentation
• Lack of a function that permit to read/write multiple non-connected variables with a single request to the plc.

Documentation on the driver and S7 protocol

The documentation of S7.Net is here.

S7.Net exposes a class called Plc that contains all the methods that we can use to communicate with the plc:

public class Plc 
{
    public string IP { get; set; }
    public bool IsConnected { get; }
    public CpuType CPU { get; set; }
    public Int16 Rack { get; set; }
    public Int16 Slot { get; set; }
    public string Name { get; set; }
    public object Tag { get; set; }
    public bool IsAvailable { get; }
    public ErrorCode Open(){...}
    public void Close(){...}
    public byte[] ReadBytes(DataType dataType, int DB, int startByteAdr, int count){...}
    public object Read(DataType dataType, int db, int startByteAdr, VarType varType, int varCount){...}
    public object Read(string variable){...}
    public object ReadStruct(Type structType, int db){...}
    public void ReadClass(object sourceClass, int db){...}
    public ErrorCode WriteBytes(DataType dataType, int db, int startByteAdr, byte[] value){...}
    public object Write(DataType dataType, int db, int startByteAdr, object value){...}
    public object Write(string variable, object value){...}
    public ErrorCode WriteStruct(object structValue, int db){...}
    public ErrorCode WriteClass(object classValue, int db){...}
    public string LastErrorString { get; }
    public ErrorCode LastErrorCode { get; }
}

To connect and disconnect you can use the Open() and Close() functions, to communicate you can use any of the methods to read and write variables from the plc memory.

Every method return an ErrorCode, or the object that it’s supposed to return if there are no errors.

Unfortunately this is quite a messy concept, because usually drivers throws exceptions in case of errors, or returns a value indicating the error and put the requested values inside a memory area passing a pointer to that area.

Here there is the documentation of the protocol, in german: http://www.bj-ig.de/service/verfuegbare-dokumentationen/s7-kommunikation/index.html

Some more documentation about the S7 protocol can be found at the snap7 website: http://snap7.sourceforge.net/ or inside the package of Snap7 full (latest full: http://sourceforge.net/projects/snap7/files/1.2.1/ )

Also some documentation on S7 protocol can be found inside LibNoDave.

Getting started with S7.Net

This paragraph explains how to get S7.Net driver and all the steps from compile the driver to add it into your application.

You can choose to add download it from NuGet (fastest way) or to include the full sources in your project.

The steps to download from NuGet are:

1) Right click on the project and select “Manage NuGet packages” NuGet 1

2) Search for S7.Net in the online tab, then install it.
NuGet 2

3) Repeat for every project where you need the dll.

These steps are to include the sources in your application:

1) Download the driver from the Github repository https://github.com/killnine/s7netplus.
S7 net download

2) Copy the S7.Net project folder in the folder that contain your project

3) Add the S7.Net project to the solution

4) Add the references

S7 Net solution reference

A simple application with S7.Net

I know that create an application to showcase the use of the driver is difficult and will not meet everyone requirements, that’s why i tried to keep it as simple as possible, just to show how to create a PLC object, how to handle a polling to refresh the data read from the PLC and how to visualize the data around the application in a simple way. Also how to write data to the PLC.

The sample application is a WPF application that can connect and disconnect from the PLC, read and write the DB1 variables on the PLC and visualize the values.

The application contains 2 projects, one is a wrapper for the plc driver, the other one is a project that contains all the graphic pages.

You can download the sample application on GitHub: https://github.com/mesta1/S7.Net-example.

S7 Net UI example

Creating a wrapper of S7.Net

Using a wrapper for the plc driver is a strategy that I usually use to implement features that the plc driver doesn’t contain, and to abstract the most of the code required to interface the application with the plc driver.

The wrapper exposes an interface IPlcSyncDriver that contains all the methods needed to communicate with the PLC:

  • connect/disconnect and connection state
  • read/write single and multiple variables, called Tags (a Tag is an object that contains an address and a value)
  • read/write a class (special feature of the S7.Net protocol)
public interface IPlcSyncDriver
{        
    ConnectionStates ConnectionState { get; }    
    void Connect(); 
    void Disconnect();      
    List<Tag> ReadItems(List<Tag> itemList); 
    void ReadClass(object sourceClass, int db); 
    void WriteItems(List<Tag> itemList); 
}   

As you can see this methods are less and differents from the ones named inside the IPlc interface of the driver, and the reason is because I handle the communication errors by throwing exceptions, so the returned values can be just the objects that i need.

Also I just use the highest level features of the driver, and handle all the complexity inside the wrapper.

I use the concept of Tags inside my wrapper, where a Tag is an object containing an address and a value. This is familiar if you already used OPC Servers and Clients, but here it is much more simple and basic.

Creation of PLC class inside the main project

In the main project I usually define the class that contains the PLC values and communication thread in a singleton.

You can read more about it in this article:
http://www.mesta-automation.com/writing-your-first-hmi-project-in-c-wpf/

You can find the plc class inside PlcConnectivity folder.

The class exposes the properties and methods that are used in all application to communicate with the PLC:

public ConnectionStates ConnectionState 
public DB1 Db1  
public TimeSpan CycleReadTime 

public void Connect(string ipAddress)
public void Disconnect()
public void Write(string name, object value)
public void Write(List<Tag> tags)

Inside the class there is a multi-threaded timer that will poll the plc once every 100 ms (see constructor).

The timer callback is responsible to refresh the tags and to calculate the time passed after every read.

You can of course use multiple timers, with different Interval value, to better manage the network resources.

private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{            
    if (plcDriver == null || plcDriver.ConnectionState != ConnectionStates.Online)
    {
        return;
    }
    timer.Enabled = false;
    CycleReadTime = DateTime.Now - lastReadTime;
    try            
    {                
        RefreshTags();
    }            
    finally 
    {
        timer.Enabled = true;
        lastReadTime = DateTime.Now;
    }
}

To read values from the PLC I use the feature that read a class directly from a DB.

private void RefreshTags()
{
    plcDriver.ReadClass(Db1, 1);
}

Write values on the PLC

To write the variables I use the method that permit to write a single object by giving an address and a value:

	
Plc.Instance.Write(PlcTags.DwordVariable, dwordVar);

You can read an example of write and read in the handlers of the MainWindow page.

PLC data visualization

To visualize the values I used a DispatcherTimer (but you can use also MVVM and DataBinding):

void timer_Tick(object sender, EventArgs e)
{
    btnConnect.IsEnabled = Plc.Instance.ConnectionState == ConnectionStates.Offline;
    btnDisconnect.IsEnabled = Plc.Instance.ConnectionState != ConnectionStates.Offline;
    lblConnectionState.Text = Plc.Instance.ConnectionState.ToString();
    ledMachineInRun.Fill = Plc.Instance.Db1.BitVariable0 ? Brushes.Green : Brushes.Gray;
    lblSpeed.Content = Plc.Instance.Db1.IntVariable;
    lblTemperature.Content = Plc.Instance.Db1.RealVariable;
    lblAutomaticSpeed.Content = Plc.Instance.Db1.DIntVariable;
    lblSetDwordVariable.Content = Plc.Instance.Db1.DWordVariable;
    // statusbar
    lblReadTime.Text = Plc.Instance.CycleReadTime.TotalMilliseconds.ToString(CultureInfo.InvariantCulture);
}

Sample code and testing

You can download the sample application on GitHub: https://github.com/mesta1/S7.Net-example.

You can also download the sample application for plc created with Step7 5.5: S7_pro1

To test the application you can use Step7 PLCSim, the guide to connect to it via NetToPlcSim is here: http://www.mesta-automation.com/nettoplcsim-how-to-connect-step-7-plc-sim-to-scadas/

Share Button

103 comments

  1. Hey Mesta, thanks for the article. As the owner of the S7NetPlus project, I want to throw out the obligatory “I accept pull requests” for anyone who is willing to devote some time to improving the project.

    Also, I want to mention that this is actually a re-upload of the original S7Net project on CodePlex. The owner of that project gave me his blessing to fork it over to Github and pick up where he left off. He’s since moved on and wont be making changes.

    I’ve been pulled off this project for the immediate future but hope to get back to it in the spring. Prior to that, I’ll try to improve the ease of adoption by creating a NuGet package of this project. That way you don’t need to compile it yourself to use it.

    Create an issue on the GitHub page with any other requests, questions, or comments. Thanks!

    • I’m glad that you liked the article. If you are familiar with NuGet, it will be a really good addition, because as you can see the biggest pain is to compile and add S7.Net to a C# project.
      I have some small enhancement to push, but I need some time for tests. Also i’m looking on adding some documentation.
      When i will have some update, i’ll make pull request.

    • That’s great news! I will update the article as soon as possible.
      Article and sources are updated with NuGet package.

  2. Hello,

    Is there anyway to generate OnChanged events on the tags, or do you need to periodically poll the PLC for new values?

    I thought the s7 PLCs had something to allow this but im not sure.

    • With this driver you have to periodically poll the plc. You have to implement your OnChanged event in your code.
      If you check Snap7 driver, there is a Partner configuration, but I didn’t spend much time exploring that driver.

  3. Nitin Majgaonkar

    Thanks for detailed explaination and S7.net
    I followed all mentioned steps but unfortunately got stuck at one point. I continuously get one warning message
    – The referenced component ‘S7.Net’ could not be found. [S7NetWrapper]
    Request you please let me know the reason behind it.

    Thanks in advance.

    Regards,
    NM

    • It’s because you have to restore NuGet package. Right click on solution, select “Manage NuGet package for solution”, push “Restore” button in the up-right part of the window that pop out.
      Then recompile the solution and it should work.

  4. Hi, mesto. i have a question on this step: 1) Right click on the project and select “Manage NuGet packages” hwo can i find this project?

    • In the menu on top of Visual Studio 2013, there is File, Edit, View, Project, …
      Then click on Project and near the bottom there is Manage NuGet packages.
      You can do this also in Solution Explorer.

      • Thanks for your reply. I have downloaded the driver. I have a case here, what should I do if visual studio and Step 7 in two computers? Thanks!

        • You don’t need step7 installed to make it work, and if you don’t have Visual Studio installed, you can just take the compiled binaries and run the software in the pc that has Step7.

        • Thanks. But where is the compiled binaries? Could you send me the link? Appreciate for your help!

  5. Hi, Mr. Mesto.

    1. PLC simulator. When I open the project, open plcsim, download. it’s running. But when monitor the DB1 block, no value change? should I input some variable(tried to insert bit memory, not work)?

    2. I have installed visual studio express 2013. when running your app., on the HMI, click ”connect”, it says ”connection error”.

    Thanks!

    • Hello,
      1. Siemens PLCSim doesn’t expose a TCP/IP interface. If you are using Step7 you can use this program: http://www.mesta-automation.com/nettoplcsim-how-to-connect-step-7-plc-sim-to-scadas/

      2. I don’t support Visual studio 2013 express, you should download Visual Studio 2013 community edition. About the communication error, you have to debug your solution step by step, probably adding the sources of S7.Net, instead of the NuGet package.

      • Thanks for reply.

        1. I have followed your link. After setup a local 127.0.0.1 and restart server(Nettoplcsim-S7o-v-0-9-5), the connection error is gone, but no data got from PLCsim(PLCsim is running and I can see there are always 0 for all the four parameters in DB1).

        Another question: what is the usage of this package: Nettoplcsim-S7o-v-0-9-5-src?

        Thanks.

  6. Hi.

    I did not see it listed, but I was wondering if this also works on the siemens softPLC, or just on hw PLCs?
    WIinAC RTX for example?

    Great article by the way.

    • Hi, this is an implementation of S7 protocol, so if your plcs use this protocol to communicate with Step7 or TIA Portal, you can talk to them.

      • i notice in the code that we have to specify cpu type.
        200/300/400 etc.

        any idea how this would work with a softplc?
        in simatic manager main window, where you insert plc type, the softplc is under pc station.

        • If the soft plc has an IP address, then you can just try to connect it by using the S7-300, that it’s the default.

  7. Hello,

    I could make the connection with the plc.

    But I do not understand how to read or write information from the application that gave the example no matter the value set data always gets me Error not found

    • My plc is S7-1500er i can connected but when i tried to put start always enter in the throw validation of:

      object value = tag.ItemValue;
      if (tag.ItemValue is double)
      {
          var bytes = S7.Net.Types.Double.ToByteArray((double)tag.ItemValue);
          value = S7.Net.Types.DWord.FromByteArray(bytes);
      }
      else if (tag.ItemValue is bool)
      {
          value = (bool)tag.ItemValue ? 1 : 0;
      }
      var result = client.Write(tag.ItemName, value);
      if (result is ErrorCode && (ErrorCode)result != ErrorCode.NoError)
      {
          throw new Exception(((ErrorCode)result).ToString() + "\n" + "Tag: " + tag.ItemName);
      }
      

      could you tell me in the start button its correct use for my plc that:

      Plc.Instance.Write(PlcTags.BitVariable, 0.0);
      

      Because always have error.
      So i want to know if i have to change for my plc the PlcTags or send any value or something i do wrong.

      And when its started how i can write/read data from the plc.

      Please Answer me

      • S7.Net doesn’t support S7-1500, but you can edit the sources to support it.
        You have to download the sources and add them in the project, instead of the sources that you downloaded from NuGet.
        In the function

        public ErrorCode Open()

        you have to add:

        case CpuType.S71500:
            // Eigener Tsap
            bSend1[11] = 193;
            bSend1[12] = 2;
            bSend1[13] = 0x10;
            bSend1[14] = 0x2;
            // Fremder Tsap
            bSend1[15] = 194;
            bSend1[16] = 2;
            bSend1[17] = 0x3;
            bSend1[18] = 0x0;
            break;
        

        after all the list of supported plc.
        Then in my application example you have to target the S7 1500 by editing the sources.
        Refer to this thread if you need the complete implementation:
        https://github.com/killnine/s7netplus/issues/21

      • Also the S7-1200 and 1500 has to be configured properly.
        Refer to http://snap7.sourceforge.net/
        and go on left menu on
        Snap7 Communication
        Snap7Client
        Overview
        and scroll to the bottom to see a guide for s7 1200 and 1500.

        • Thks to the help now i update the source code of the dll code increasing but still has the same error and will not let me start.

          Might help me with the topic I’m learning about this and need solving.

          Again enter in the throw:

          if (result is ErrorCode && (ErrorCode)result != ErrorCode.NoError)
          {
              throw new Exception(((ErrorCode)result).ToString() + “\n” + “Tag: ” + tag.ItemName);
          }
          

          So maybe i send bad to start:

          (contained of startbutton== Plc.Instance.Write(PlcTags.BitVariable, 0.0);)

          Or i have to do another change in the code of the dll could you indicate me what i have to do to resolve please.

        • The sample application was done to read memory from the PLC program made for Step 7 v 5.5.
          If you don’t have a DB1 in your plc, probably it crashes because the plc tries to read DB1 but can’t find it.
          Did you replicate the DB structures as they are in the S7_pro1 project ?
          Also did you configure the DB as Snap7 documentation suggested ?

        • ok let me explain i have to connect with a plc to write and read data.

          That plc S7-1500 with rack=0 and slot:1 and
          in the plc i created a datablock for you to write in: this is DB5
          and a datablock for you to read in it: this is DB6
          OpArea: AREA_DATA
          (this means you want to read in a data block, area_in for example would mean you directly want to read an digital input port from the plc)

          DBNr. 6
          (as i sad, i prepared the plc here so that you can read in db 6 and write in db 5

          OpType: TYP_BIT
          (here you can input what typ of data you want to read..in this first case we just want to read a single bit with1 or 0)

          OpAnz: 1
          (in this case: is the number of bits we want to read, fo rexample: if you read 8 bits here..would be the same result as if you would read OpAnz 1 with OpType Byte )

          Offset: 0
          (this is kind of internal adress of the bits in the chossen db. you can see the offset in the picture i attached. the offset you enter here is the number before the dot=

          Bitnr: 0
          (this is the second part of the offset and the number after the dot. per offset you can have bits from 0..7 before you increase the offset.

          So now you want to read in DB6 Bit 0.0
          As an result you should get 1 or 0

          The plc Imput its: 9kW1wkL.png

          So, I connected with that the example do the connection modified the system and update the dll with new Enum, etc.

          When i tried do the start in the project for read the data (i guest) i got that error.

          Sorry, I don’t see the structure of S7_pro1 project.

          Pls could you tell me if i’m connected why i can’t read the data? maybe it’s the another form so, you have any source or example to that

        • On S7.Net sources, there is a project called UnitTest.
          On that project you find a simple usage of the library.
          Just make a simple application with a code like this:

          Plc plc;
          plc = new Plc(CpuType.S71500, “127.0.0.1”, 0, 2);
          var error = plc.Open();

          Check that there are no errors, of course you have to insert the correct IP, etc…

          ushort result = (ushort)plc.Read(“DB5.DBW2”);
          Console.WriteLine(result);
          // expected 0

          ushort val = 40000;
          plc.Write(“DB5.DBW2”, val);

          result = (ushort)plc.Read(“DB5.DBW2”);
          Console.WriteLine(result);
          // expected 40000

        • Probably you also need to specify slot = 0 and rack = 0 when you create the plc.
          like this:
          plc = new Plc(CpuType.S71500, “127.0.0.1”, 0, 0);
          Because as I read on other forums, S7 1200 and S7 1500 accept only this configuration.
          Make some tests and let me know, unfortunately i don’t have a S7 1500 CPU right now.

        • ok i do the test i recived that:

          Z4Tc1nU.jpg

          so, could you tell me i write the 4000 and -100 into the plc?

          that’s right?

        • Yes you can put a breakpoint, go online with the plc and see if the memory changes.

        • ok tell one more thing if i wanna write in the plc (“DB5”) i have to use : (“DB5.DBW2”) so if i understand to read the plc (“DB6”) i have to use Read(“DB6.DBW2”);….

          that’s right?.

        • Yes but you are reading only the word DBW 2.0.
          Now that you get started you can experiment by yourself, just by checkIng the code in the unit tests and in my example application.

        • Mesta you have any mail to contact you because i have to do some question about’s the offset values to read/Write that’s values in the plc or write me to a mail y.yanten@ottcomputer.ec pls

        • You can contact me with this: http://www.mesta-automation.com/contact/
          But please try to use comments, so other people can read it.

        • I try to explain to your response to comments can be read by all and facilitate future developments.

          Are assumed to have read values are DB6.XXX corresponding to the values of “DB_PLC_Input” so my serious question:

          “Bool_Bit” How can I read / write these variables and how would represent by analogy to the example.
          “Word_Number” equals “World Variable” and is represented with “DB6.DBD4”
          “Double_Int_Number” it represents “DB6.DBD6”, is that correct?

          In other words if I want to read “DB_PLC_Input” I change the last value with the offset value assigned?

          Attached image I hope to help dispel doubts

          PLCSoft2.jpg

        • The driver reads and writes bytes.
          If you want to read the Bool_Bit, offset 0.0, you should write DB5.DBX0.0 (1 bit)
          If you want to read the Word_Number,offset 2.0, you should write DB5.DBW2 (2 bytes)
          If you want to read the Int_Number,offset 4.0, you should write DB5.DBW4 (2 bytes) + conversion.
          If you want to read the Double_Number,offset 6.0, you should write DB5.DBB6 (4 bytes) + conversion
          If you want to read the Real_Number,offset 10.0, you should write DB5.DBB10 (4 bytes) + conversion
          String and char are not supported at the moment, maybe someone will add a patch in the future.
          If you want to read Date_Time_Bit, you should write DB5.DBX20.0 (1 bit)
          Usually it’s best to read everything in one shot, by using read class or read struct, or read bytes and get the array of bytes.
          The conversion that you need are all in the driver and you can check the Unit tests to see how to use to convert from bytes to real, int, dint and so on…

  8. Hi mesta
    I configure the DB snap7 documentation suggested
    but i dont know DB configure in plc ? Should i some varieable (memory input)
    i connect plc s7 1200 to app= connect
    then i will start but error
    why ?

  9. hi,
    I am a complete dummy on this matters. Thank you for the article. I have a question: I need, physically, to send an open/close operation, I mean to set the values to 0 or 1. How can I do this? Can I do it with Write method?

    • Hi Daniela, to get started with simple communication you can download the sources (https://goo.gl/LeZkbk) and look into unit tests. Write should work for bits, here is an example about integer:

      ushort val = 40000;
      plc.Write("DB1.DBW0", val);
      ushort result = (ushort)plc.Read("DB1.DBW0");
      
  10. Plc.DB1.cs :The following code was added.

    // DB1.DBX16.0
    public bool BitVariable160 { get; set; }
    public bool BitVariable161 { get; set; }
    public bool BitVariable162 { get; set; }
    

    PlcTag.cs :The following code was added.

    public const string BitVariable160 = "DB1.DBX16.0";
    

    MainWindow.xaml.cs : The following code was added.

     void timer_Tick(object sender, EventArgs e)
    {
      ledMachineInRun.Fill = Plc.Instance.Db1.BitVariable160 ? Brushes.Green : Brushes.Gray;
    } 
    /// Writes a bit to 1      
    private void btnStart2_Click(object sender, EventArgs e)
    {
        Plc.Instance.Write(PlcTags.BitVariable160, 1);
        textBox1.Text = Plc.Instance.Db1.BitVariable160.ToString();               
    }
    /// Writes a bit to 0        
    private void btnStop2_Click(object sender, EventArgs e)
    {       
        Plc.Instance.Write(PlcTags.BitVariable160, 0);
        textBox1.Text = Plc.Instance.Db1.BitVariable160.ToString();
    }
    

    From the PLC, it is possible to read and write. However, the C # program does not read.
    Why is this?

  11. Cesar Sosa Zuñiga

    Hi, I’ve been working with a simiens s7 1200 and a C# interface but i noticed some problems or bugs, i don’t know. Let me explain it: I’ve been working in existing network in a hub node so my plc communicates with the s71200 through a 8 ports hub. In my first release of my HMI with C# everything was doing fine but later i updated my software to increase it performance performance but i discovered that sometimes my pc can’t communicate with the plc during one or two seconds. i.e. my code has a 2 seconds timer that verify if the PLc is available and if it connectable. the problem come when i can read that is available but as i mentioned before it is not connectable. trying to find a solution I used the step by step instruction to see what was going wrong:

                    if (plc.IsAvailable)
                    {
                        ErrorCode connectionResult = plc.Open(); //open connection
                        if (connectionResult.Equals(ErrorCode.NoError))
                        {
                            gB_Control.Enabled = true;
                            ts_ProgressBar.Value = 100;
                            tSrip_Conectado.Text = "A Text";
                        }
                        else
                        {
                            ts_ProgressBar.Value = 0;
                            tSrip_Conectado.Text = "B text";
                        }
                        plc.Close(); //close connection
                    }
                    else
                    {
                        ts_ProgressBar.Value = 0;
                        tSrip_Conectado.Text = "C Text";
                    }
                }
    

    usually i get the A text but some times i get the b Text and i don’t know why. after a few tests the plc got frozen, and the pc wasn’t able to get connected with the plc so my code only returns me the b text. i solve it formatting the plc.

    Right now i just want to know where it can be the problem.

    • Why are you opening the socket every time you start a communication ? You can keep the socket open and just close it if the plc doesn’t respond or if you close the communication. Did you try to keep the socket open ? Also check LastErrorString variable, it if contains some informations.

  12. Hello Mesta, excellent work you are doing!. I have just two doubts / questions (S7-1200) :

    1 – Do we need to activate PLC for working with this program ? do we need to put some blocks ?
    2 -Where can I find offset / address of this tags in DB: (I can see adress it only in Default tag table but in DB can’t see.
    https://goo.gl/photos/z64FgbnjtdRo1AxV7

    I had to change for: plcDriver = new S7NetPlcDriver(CpuType.S71200, ipAddress, 0, 1);
    I can connect, but I see only 0 https://goo.gl/photos/rUxW5MrUioDe3fhU8

    Best regards.

  13. Hi i’m using vs2010 and Nuget, but S7.net simply doesnt show up when i would like to add this to my project.
    Is Visual studio 2010 not supported ?

    • VS 2010 should be supported, but I don’t know if the NuGet package was made compatible with VS 2010. Try to download the sources, compile in VS2010 and add the project directly into your application. Sources should be compatible also with .Net 3.5.

  14. Hi mesta,
    Thanks for this libraray projects.If u can do one video for how connect ,read,write and plc part too.we are reading reading but can’t achieve.Please in your video do tia portal as simulation and c# part.Like many people will understand and not ask so many question.Video is best training.
    thanks

  15. please do one video training with tia portal in local tcp/ip

  16. can i have an example on how to connect to omron plc using modbus tcp/ip in c# ?

    your blog is a life saver.

  17. Hi.
    Great work thank you!
    I have a question, how would you do to save data from a DB inside of a Database? It would be nice if you would have ideas 🙂

    Thanks!

    • I usually save alarms and events on a database, and I do that just by polling the plc and checking if there are some of them active that I didn’t recorded already.
      How I save these, it depends on the type of database, type of data, etc…

      • Hi Mesta,

        When you are saving alarms and events on a database, how do you do to avoid writing inside the database the same alarm each time the timer is checking the status of the PLC?

        Thanks 🙂

        • Hi, for alarms and events logging I use a dedicated class/thread indipendent from the plc, because there can be multiple plcs but the alarm logging is always a single part of the application.
          In the plc class I poll the plc to know the current state of the alarm, if it’s active or not.
          In the alarm logging class I scan the plc alarms to check if they are active or inactive. Once an alarm on the plc become active (from 0 to 1) I log it in the database and mark it with an “acknowledged” flag. When it becomes inactive (from 1 to 0) I reset the “acknowledged” flag.

  18. Hi mesta,
    Thank you for introducing this useful library. I am now trying s7netplus and have a question, I am using s7-1200 PLC and checked ip(“192.168.0.51”), rack(0) and slot(1) from TIA portal. But I get ErrorCode = ConnectionError when trying to establish a connection.
    Instead, I get no error with rack = 0 and slot = 0, but always have an ErrorCode = WrongVarFormat from reading anything, for example, “var data = plc.Read(“MD5642″);”. Did I do anything wrong? Thank you.

    • It’s a matter of conversion. Try to download the sources and look at unit tests. Writing the documentation is the next step that we are addressing.

  19. Hello, I’m now using this nice library, strangely, I’ve some incoherent values.
    I would like to get the DWord DB172.DW1 value, the first value represents a quantity, the second value is either 0 or 1,my syntax like this like (in vb.net) :
    Dim result as Object = MyPLC(“DB172.DBW1″)
    MsgBox(result.ToString & ” ” & result.GetType.ToString)

    I obtain as displayed message :
    12 System.UInt16

    On DB172.DBW2, I obtain this one :
    3073 System.UInt16

    What am I doing wrong? Thanks

    • Hello, you should specify what values you see on the plc, what you see from the library and what function of S7.Net you are using. Probably you need to check that you are reading the exact word and bytes, and using a correct conversion. Check the documenation to see how to make a proper conversion.

  20. Alberto Acerbis

    Hi mesta,
    I try to use your great library. I haven’t problem to connect to PLC, but everytime I try to read a variable, or set one, I have an error message “WriteData”.
    After this operation I don’t see any change in my PLC.
    Did I do anything wrong? Thank you

    • Hello, you should download the sources and go through the code to check what’s wrong. Actually this may happen from a number of reasons depending on your code. Also if you are using S7 1200/1500 check the documentation to set the DB with Full access.

  21. Hello, how i can read input, output and merkers ? the read/write DB it is ok.
    Thanks a lot.
    Mark

    • s7 1200 adn s7 300

      • Hello, you can specify the datatype that you want to read in ReadBytes, and use the start byte address field to specify from where to start.

        • Please can you post an example ? Thanks a lot.

        • int val = 1;
          plc.Write("M0.0", val);
          bool result = (bool)plc.Read("M0.0");
          
        • this code does not work. there’s not a write/read in the sample project. what can i do ?
          Thanks a lot!

        • Hello Mark, the sample project shows how to use the S7.Net driver to build your application, it is not intended to be adopted as a general architecture for an HMI, as it is too simplistic.

          The code works with the S7.Net driver, but in the example the driver is abstracted away to show how to make an abstraction on the driver and implement just what you need.

          If you don’t need the abstraction, you can just replace everything with direct calls to the S7.Net driver, without extra-classes, interfaces and so on.
          This will make your life easier for the first steps.

  22. hello! Another question : i see that with the s7 300 the led machine in the project, change color by the bit DB1.DBX0.0 (green If i set it with start button and gray If i reset bit with stop button). With s71200 it is always gray but the DB1.DBX0.0 bit change it status. What i do to get the same in 1200? Thanks a lot!
    Mark

    • Update:

      i test the connection a lot of time and with the s7 300 no problem.
      with the 1200, in the project i change cpu type, 0 , 1 and in plc program access on DB etc…
      but when i try debug mode, in the label i can’t see the value that i write in the DB. the label value it’s always 0.
      Also the led machine is always gray.
      What can i do ?
      excuse me but i am a beginner with plc !
      Thanks a lot.

    • plc = new Plc(CpuType.S71200, “ip address here”, 0, 0);

      plc = new Plc(CpuType.S71200, “ip address here”, 0, 1);

      i tried both, alway connect but i have always this

      https://goo.gl/photos/rUxW5MrUioDe3fhU8

      on tia portal i see the change of value when i write in the textbox but on the application i read always 0.
      Best Regards.
      Mark.

  23. Mesta, i found the error. In my plc program i’ve committed an issue. Now i can see and write all from the application. I have another question : if i write a value in textbox from the solution, i read it in plc in real time, but if i write a value on db by tia portal, i can not see it in my application. why ? thanks a lot for your disponibility.

  24. I see that in s7_pro (the program plc), in OB1 there are some instructions that must be copied to plc program.
    Now i create an ellipse and two button, one for set and one for reset a merker on plc.
    From Tia portal i can see the value of merker changing, but my ellipse doesen’t change color.
    Can you help me with code to read from plc ?
    Thanks a lot.
    Regards!

  25. Hi,

    We’re struggling to read any data in DataBlocks using this project and a S7-1200 PLC.
    Stepping through the source code we always receive the error “WrongNumberReceivedBytes” which is here in PLC.cs line number 332.

    “int numReceived = _mSocket.Receive(bReceive, 512, SocketFlags.None);
    if (bReceive[21] != 0xff)
    throw new Exception(ErrorCode.WrongNumberReceivedBytes.ToString());

    We are calling “ushort result = (ushort)plc.Read(“DB120.DBW4″);” which exists in the PLC datablock.

    Is there an error with the number of bytes being sent in the “_mSocket.Send(package.array, package.array.Length, SocketFlags.None);” method causing the PLC to respond with the error?

    Many Thanks
    Tom

  26. Hi,
    i’m using S7.NET driver to read variables from S7300.
    I don’t understand how to show real value of a counter.

    Example: i put in a VAT the variable DB12.DBW0 (defined as WORD in Simatic)
    If i show it as a counter i see 98 (the real value), while if i show it as decimal i see the value 152.

    In my C# project i would like to show the real value (98), but i alway see 152:
    I convert the value from plc in this way:
    var valueCounter = (ushort) S7.Net.Types.Counter.FromByteArray(lst.Skip(0).Take(2).ToArray());

    Someone can help me?
    Many Thanks
    Francesco

  27. solved in this way:

    I read from plc in this way:
    ushort valueCounter = S7.Net.Types.Word.FromByteArray(lst.Skip(0).Take(2).ToArray());

    and the i convert in this way:
    txtCounter.text = valueCounter.ToString(“X”);

    So in my text field i visualize the real value of the counter.

    I don’t know if there is a better way, but this works. Howewer any suggestion is welcome.
    ciao

  28. HI, let’s speak about timers…

    I defined in S7-300 a DB with inside an array of “S5TIME”.

    When i try to READ the value of one variable all works fine and a see in my double variable in c# the correct value in seconds (in the format x.xx sec). For this i use this conversion:

    var valueTmr = S7.Net.Types.Timer.FromByteArray(lst.Skip(0).Take(2).ToArray());
    rr.SetField(“PLC”, valueTmr);

    My problem is when i try to do the opposit conversion (WRITE in the PLC). I’m not able to find the correct way to convert a double variable from c# to byte array for PLC. I tried a lots of way but i didn’t find the correct one.

    Some one can help me?

    best regards
    Francesco

    • I don’t have a plc to make a test right now, but it seems that you should use a double.

      var bytes = Types.Double.ToByteArray((double)value);

      • unfortunatly your suggestion doesn’t work. Remember that is not a simple conversion between differents types. Infact you have to implement resolution bits.
        S5TIME variable must have this format:
        W#16#tXYZ
        where:
        – “t” is the time resolution (xx00 = 10 msec, xx01 = 100 msec, xx10 = 1 sec, xx11 = 10 sec)
        – “XYZ” is the BCD value

        • I solved with the belowe function.
          Consider if it’s useful to introduce this function in your library.
          ciao
          Francesco

          public static byte[] ConvertDoubleToS5T(double value)
          {

          double cvalue = value * 100;
          int ivalue = (int)cvalue;
          byte[] bcd = new byte[4];
          byte[] S5TWORD = new byte[2];

          if (ivalue 999000) ivalue = 999000;

          if (ivalue 999) & (ivalue 9990) & (ivalue 99900) & (ivalue 0; i–)
          {
          bcd[i] = (byte)(ivalue % 10);
          ivalue /= 10;
          }

          S5TWORD[0] = (byte)(bcd[1]);
          S5TWORD[0] += (byte)(bcd[0] << 4);

          S5TWORD[1] = (byte)(bcd[3]);
          S5TWORD[1] += (byte)(bcd[2] << 4);

          return S5TWORD;
          }

        • sorry, but the the cut&paste did’t work well, i try to post the code again…

          public static byte[] ConvertDoubleToS5T(double value)
          {

          double cvalue = value * 100;
          int ivalue = (int)cvalue;
          byte[] bcd = new byte[4];
          byte[] S5TWORD = new byte[2];

          if (ivalue 999000) ivalue = 999000;

          if (ivalue 999) & (ivalue 9990) & (ivalue 99900) & (ivalue 0; i–)
          {
          bcd[i] = (byte)(ivalue % 10);
          ivalue /= 10;
          }

          S5TWORD[0] = (byte)(bcd[1]);
          S5TWORD[0] += (byte)(bcd[0] << 4);

          S5TWORD[1] = (byte)(bcd[3]);
          S5TWORD[1] += (byte)(bcd[2] << 4);

          return S5TWORD;
          }

        • No, i don’t know why but the code you see in the comment is not the one that i introduced.
          However, if some one is interested in it i can send it in an alternative way

        • Open a pull request on github.

  29. Hi Mesta,

    I am trying exactly same stuff you are doing in the video. I have created Data_block_1[DB1] in TIA Portal V13. I unchecked the optimization block access property as you have said. Then I have enabled full access, and I have permitted PUTGET communication. I have only 3 integers in DB1 block named int1, int2 and int3 occupying offset values of 0.0, 2.0 and 3.0 respectively. I have established communication of PLC with my PC with no problem at all. I can monitor the values in TIA Portal. Address IP of PLC is 192.168.0.101 Then I started writing the code you have written after downloading S7 NuGet package. I have built the program with no errors. Now I will try to read DB1.DBW0.0, int1.

    Here is the code :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using S7.Net;

    namespace ConsoleApplication1
    {
    class Program
    {
    static void Main(string[] args)
    {
    using (var plc = new Plc(CpuType.S71200, “192.168.0.101”, 0, 1))
    {
    plc.Open();

    var intVariable = (ushort)plc.Read(“DB1.DBW0.0”);
    Console.WriteLine(“DB1.DBW0.0: ” + intVariable);
    Console.ReadKey();
    }
    }
    }
    }

    But when I execute the program, I get an error saying that :

    InvalidCastException was unhandled
    An unhandled exception of type ‘System.InvalidCastException’ occurred in ConsoleApplication1.exe

    I don’t know how I can get this error when I did exactly what you have done.

    Thanks in advance Mesta.

  30. How can I connect my PLC Modicon M340 with C#?.
    I have searched a lot but no way.

Leave a Reply