How do I connect to device using jamod and interpret the data - java
My client wants to control the HVAC systems installed in their site with a custom solution. The HVAC devices provide MODBUS TCP/IP connectivity. I'm new to this field and have no knowledge of MODBUS. I searched the internet and found jamod as a java library for MODBUS. Now I would like to write a program using jamod. But my confusion is how do I get the address of the device I want to connect. And my second problem is even if I manage to connect the device , how can I get required data (in engineering units like temperature) from MODBUS. My questions may sound awful but please forgive me as I'm a novice in this field.
How do I get the address of the device I want to connect to?
This kind of depends on if you're connecting over Modbus RTU or Modbus TCP. RTU (serial) will have a slave id you'll specify while tcp is more direct and the slave id should always be 1.
How can I get required data (in engineering units like temperature) from MODBUS?
Hopefully the data is already formatted in engineering units. Check the device's manual and there should be a table or chart mapping registers to values.
Example:
String portname = "COM1"; //the name of the serial port to be used
int unitid = 1; //the unit identifier we will be talking to, see the first question
int ref = 0; //the reference, where to start reading from
int count = 0; //the count of IR's to read
int repeat = 1; //a loop for repeating the transaction
// setup the modbus master
ModbusCoupler.createModbusCoupler(null);
ModbusCoupler.getReference().setUnitID(1); <-- this is the master id and it doesn't really matter
// setup serial parameters
SerialParameters params = new SerialParameters();
params.setPortName(portname);
params.setBaudRate(9600);
params.setDatabits(8);
params.setParity("None");
params.setStopbits(1);
params.setEncoding("ascii");
params.setEcho(false);
// open the connection
con = new SerialConnection(params);
con.open();
// prepare a request
req = new ReadInputRegistersRequest(ref, count);
req.setUnitID(unitid); // <-- remember, this is the slave id from the first connection
req.setHeadless();
// prepare a transaction
trans = new ModbusSerialTransaction(con);
trans.setRequest(req);
// execute the transaction repeat times because serial connections arn't exactly trustworthy...
int k = 0;
do {
trans.execute();
res = (ReadInputRegistersResponse) trans.getResponse();
for (int n = 0; n < res.getWordCount(); n++) {
System.out.println("Word " + n + "=" + res.getRegisterValue(n));
}
k++;
} while (k < repeat);
// close the connection
con.close();
First, "address" is ambiguous when you're working with Modbus/TCP since there is the IP address of the slave, the unit number of the thing you're talking to (typically 0 for Modbus/TCP), and the address of any registers.
For the "engineering units" question, what you're going to want is the Modbus register map, with any units or conversion factors included. You may also need to know data types, since all Modbus registers are 16 bits.
Related
How to get the current number of messages in a jms topic on IBM WAS
I need to create a REST service in the Java programming language that receives JMS connection factory's JNDI name and JMS topic's JNDI name as input and should return the number of messages in the resource at the moment. The problem is getting the length of the topic from IBM WAS. I know about the existence of TopicBrowser from Oracle, with which you can get all the messages in the topic and just count their number. But for some reason, we do not use it. My idea is to get the SIB Destination queue length property, which is located in: Buses> Bus> Recipients> MyTopic.Space> Publication Points, in the web console. I use: IBM WAS 9.0. ND. Default Message Provider. I will be glad to any advice.
You can get the state of a subscriber using the admin client for example: // Start by querying the objectName of the Publication Point (Topic Space on a specific node). AdminClient adminClient = AdminClientFactory.createAdminClient(connectProps); StringBuffer oNameQuery= new StringBuffer(); oNameQuery.append(adminClient.getDomainName()).append(":*"); oNameQuery.append(",type=").append("SIBPublicationPoint"); oNameQuery.append(",name=").append("Default.Topic.Space"); oNameQuery.append(",node=").append(nodeName); oNameQuery.append(",process=").append("server1"); oSet= adminClient.queryNames(new ObjectName(oNameQuery.toString()), null); ObjectName defaultTopicSpaceOn = (ObjectName) oSet.iterator().next(); System.out.println("Default.Topic.Space ObjectName:"+defaultTopicSpaceOn); // Then look at each subscription storing messages in the Publication Point. Long depth = (Long) adminClient.invoke (defaultTopicSpaceOn, "getDepth", null, null); System.out.println("DefaultTopicSpace Depth:"+depth+"\n"); SIBSubscription[] subscriptions = (SIBSubscription[]) adminClient.invoke (defaultTopicSpaceOn, "getSubscriptions", null, null); for (SIBSubscription subscription : subscriptions) { System.out.print("DefaultTopicSpace Subscription:"+subscription.getName() +" Id:"+subscription.getId() +" SubscriberId:"+subscription.getSubscriberId() +" Selector:"+subscription.getSelector() +" Depth:"+subscription.getDepth()); for (String topicName: subscription.getTopics()) System.out.print(" Topic:"+topicName); System.out.println(); } This produces something like: DefaultTopicSpace Depth:2 DefaultTopicSpace Subscription:Default.Topic.Space Id:21974964F5B726A6C21C7E59 SubscriberId:jmsThinClient.JMSSendReceiveclientID##jmsThinClient.JMSSendReceiveSubscription Selector:null Depth:2 Topic:Topic1/* Api doc:https://www.ibm.com/support/knowledgecenter/SSEQTP_8.5.5/com.ibm.websphere.javadoc.doc/web/apidocs/com/ibm/websphere/sib/admin/package-summary.html
Use dnsjava to get hostname from ip address from 192.168.1.1 to 192.168.1.254
I am trying to use dnsjava in an android app to find hostnames of devices in my local wifi network. Below is the code used: try { String ipAddress = "33.1.168.192"; String dnsblDomain = "in-addr.arpa"; Record[] records; Lookup lookup = new Lookup(ipAddress + "." + dnsblDomain, Type.PTR); SimpleResolver resolver = new SimpleResolver(); resolver.setAddress(InetAddress.getByName("192.168.1.1")); lookup.setResolver(resolver); records = lookup.run(); if(lookup.getResult() == Lookup.SUCCESSFUL) { for (int i = 0; i < records.length; i++) { if(records[i] instanceof PTRRecord) { PTRRecord ptr = (PTRRecord) records[i]; System.out.println("DNS Record: " + records[0].rdataToString()); } } } else { System.out.println("Failed lookup"); } } catch(Exception e) { System.out.println("Exception: " + e); } The code was taken from the below link and it seems to work there for OP: any way to discover Android devices on your network? 192.168.1.33 is an active device on my wifi network . 192.168.1.1 is the router IP . The code reaches "Failed lookup" everytime . I am not sure where I am going wrong as I am new to dnsJava and Networks. An additional question is , will this yield perfect result when scanned over all 254 ip's ? I am thinking of using this code in prod and need to be sure of that . Any help is very much appreciated.
PTR records for reverse names are not stored in the order you're thinking. In general terms for IP A.B.C.D you need to resolve D.C.B.A.in-addr.arpa, so you'll need to reverse the order of the IP components.
RIAK high diskspace usage
I am evaluating RIAK kV V2.1.1 on a local desktop using java client and a little customised version of the sample code And my concern is I found it to be taking almost 920bytes per KV. That's too steep. The data dir was 93 mb for 100k kvs and kept increasing linearly there after for every 100k Store ops. Is that expected. RiakCluster cluster = setUpCluster(); RiakClient client = new RiakClient(cluster); System.out.println("Client object successfully created"); Namespace quotesBucket = new Namespace("quotes2"); long start = System.currentTimeMillis(); for(int i=0; i< 100000; i++){ RiakObject quoteObject = new RiakObject().setContentType("text/plain").setValue(BinaryValue.create("You're dangerous, Maverick")); Location quoteObjectLocation = new Location(quotesBucket, ("Ice"+i)); StoreValue storeOp = new StoreValue.Builder(quoteObject).withLocation(quoteObjectLocation).build(); StoreValue.Response storeOpResp = client.execute(storeOp); }
There was a thread on the riak users mailing list a while back that discussed the overhead of the riak object, estimating it at ~400 bytes per object. However, that was before the new object format was introduced, so it is outdated. Here is a fresh look. First we need a local client (node1#127.0.0.1)1> {ok,C}=riak:local_client(). {ok,{riak_client,['node1#127.0.0.1',undefined]}} Create a new riak object with a 0-byte value (node1#127.0.0.1)2> Obj = riak_object:new(<<"size">>,<<"key">>,<<>>). #r_object{bucket = <<"size">>,key = <<"key">>, contents = [#r_content{metadata = {dict,0,16,16,8,80,48, {[],[],[],[],[],[],[],[],[],[],[],[],[],[],...}, {{[],[],[],[],[],[],[],[],[],[],[],[],...}}}, value = <<>>}], vclock = [], updatemetadata = {dict,1,16,16,8,80,48, {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],...}, {{[],[],[],[],[],[],[],[],[],[],[],[],[],...}}}, updatevalue = undefined} The object is actually stored in a reduced binary format: (node1#127.0.0.1)3> byte_size(riak_object:to_binary(v1,Obj)). 36 That is 36 bytes overhead for just the object, but that doesn't include the metadata like last updated time or the version vector, so store it in Riak and check again. (node1#127.0.0.1)4> C:put(Obj). ok (node1#127.0.0.1)5> {ok,Obj1} = C:get(<<"size">>,<<"key">>). {ok, #r_object{bucket = <<"size">>,key = <<"key">>, contents = [#r_content{metadata = {dict,3,16,16,8,80,48, {[],[],[],[],[],[],[],[],[],[],[],[],[],[],...}, {{[],[],[],[],[],[],[],[],[],[],[[...]],[...],...}}}, value = <<>>}], vclock = [{<<204,153,66,25,119,94,124,200,0,0,156,65>>, {3,63654324108}}], updatemetadata = {dict,1,16,16,8,80,48, {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],...}, {{[],[],[],[],[],[],[],[],[],[],[],[],[],...}}}, updatevalue = undefined}} (node1#127.0.0.1)6> byte_size(riak_object:to_binary(v1,Obj)). 110 Now it is 110 bytes overhead for an empty object with a single entry in the version vector. If a subsequent put of the object is coordinated by a different vnode, it will add another entry. I've selected the bucket and key names so that the local node is not a member of the preflist, so the second put has a fair probability of being coordinated by a different node. (node1#127.0.0.1)7> C:put(Obj1). ok (node1#127.0.0.1)8> {ok,Obj2} = C:get(<<"size">>,<<"key">>). {ok, #r_object{bucket = <<"size">>,key = <<"key">>, contents = [#r_content{metadata = {dict,3,16,16,8,80,48, {[],[],[],[],[],[],[],[],[],[],[],[],[],[],...}, {{[],[],[],[],[],[],[],[],[],[],[[...]],[...],...}}}, value = <<>>}], vclock = [{<<204,153,66,25,119,94,124,200,0,0,156,65>>, {3,63654324108}}, {<<85,123,36,24,254,22,162,159,0,0,78,33>>,{1,63654324651}}], updatemetadata = {dict,1,16,16,8,80,48, {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],...}, {{[],[],[],[],[],[],[],[],[],[],[],[],[],...}}}, updatevalue = undefined}} (node1#127.0.0.1)9> byte_size(riak_object:to_binary(v1,Obj2)). 141 Which is another 31 bytes added for an additional entry in the version vector. These numbers don't include storing the actual bucket and key names with the value, or Bitcask storing them again in a hint file, so the actual space on disk would then be 2x(bucketname size + keyname size) + value overhead + file structure overhead + checksum/hash size If you're using bitcask, there is a calculator in the documentation that will help you estimate disk and memory requirements: http://docs.basho.com/riak/kv/2.2.0/setup/planning/bitcask-capacity-calc/ If you use eLevelDB, you have the option of snappy compression which could reduce the size on disk.
Modbus TCP Slave Thread - set & get registers values
According to this howToModbusSlave I am trying to build my own modbus slave with registers of chosen value (later I wanna fill these values with data from monitored device using python/jython) and send them away using Predix (cloud platform). Since I am a modbus greenhorn, I still cant find a way how to add my chosen values into my register holders. Here is the my Slave thread I use to provide data for the Master on localhost:502 : public class SimpleApp { public static void main(String args[]) { try { //1. The important instances and variables ModbusTCPListener listener = null; SimpleProcessImage spi = null; int port = 502; //2. Prepare a process image spi = new SimpleProcessImage(); //I dont understand this part, why do i need it? spi.addDigitalOut(new SimpleDigitalOut(true)); spi.addDigitalOut(new SimpleDigitalOut(false)); spi.addDigitalIn(new SimpleDigitalIn(false)); spi.addDigitalIn(new SimpleDigitalIn(true)); spi.addDigitalIn(new SimpleDigitalIn(false)); spi.addDigitalIn(new SimpleDigitalIn(true)); //setting up register holders, gonna ask no 10,11,20 and 21 as set in the data node config for (int i = 0; i < 25; i++) { int value = 15; SimpleInputRegister sr = new SimpleInputRegister(value); spi.addRegister(sr); } //3. Set the image on the coupler ModbusCoupler.getReference().setProcessImage(spi); ModbusCoupler.getReference().setMaster(false); ModbusCoupler.getReference().setUnitID(15); //15 //4. Create a listener with 3 threads in pool listener = new ModbusTCPListener(1); //no of threads listener.setPort(port); listener.start(); } catch (Exception ex) { ex.printStackTrace(); } } } Data nodes config: <channel protocol="TCP_IP" tcpIpAddress="127.0.0.1" tcpIpPort="502"> <unit id="1"> <register name="Node-1-1" dataType="INTEGER" address="10" registerType="HOLDING" description="temperature"/> <register name="Node-1-2" dataType="DECIMAL" address="11" registerType="HOLDING" description="pressure"/> </unit> <unit id="2"> <register name="Node-2-1" dataType="INTEGER" address="20" registerType="HOLDING" description="temperature"/> <register name="Node-2-2" dataType="INTEGER" address="21" registerType="HOLDING" description="pressure"/> </unit> </channel> I get theses transfers ("output"): [{"address":"com.ge.dspmicro.machineadapter.modbus://127.0.0.1:502/2/20","datatype":"INTEGER","name":"Node-2-1","category":"REAL","value":655370,"timestamp":1464006550991,"quality":"NOT_SUPPORTED (20000000) "}, {"address":"com.ge.dspmicro.machineadapter.modbus://127.0.0.1:502/1/10","datatype":"INTEGER","name":"Node-1-1","category":"REAL","value":655370,"timestamp":1464006550992,"quality":"NOT_SUPPORTED (20000000) "}] Main Questions: 1) where are the data from Node 1-2 and 2-2 (missing in the output)? 2) how can I edit the values the are sent from the registers? (why do i get "value":655370?) Optional Qustions: (things i didnt understand in documentation) 3) what does the class simpleDigitalOut/In stand for? 4) what does the ModbusCoupler.getReference().setUnitID(value) stand for? (it clearly doesnt have to do anything in common with unitID of data nodes 5) what is the difference between SimpleInputRegister and SimpleRegister class?
This is a partial answer: 1) You need to add the nodes to the dataSubscriptionConfig tag below in the config.xml file 2) Here is where you are setting the value: int value = 15; - You need to implement a way to send dynamic values
MongoDB & Java Connection Error
I am trying to run a java program with the java/mongo driver on a separate computer than the one running mongod. I only modified the java/mongo tutorial code to include an ip address. package mongotest; import com.mongodb.*; public class Main { static DBCursor cur; static DBCollection coll; public static void main(String[] args) { Mongo m; try{ m = new Mongo("192.168.0.102"); // <---- This does not connect. It will eventually time out DB db = m.getDB("playerdb"); coll = db.getCollection("players"); cur = coll.find(); //while (cur.hasNext()) // coll.remove(cur.next()); coll.ensureIndex(new BasicDBObject("playerID", 1).append("unique", true)); boolean unique = true; cur = coll.find(); printResults(cur, "Find All Records"); boolean canCreate; canCreate = createAccount("Josh", "1", cur, coll); canCreate = createAccount("Jason", "1", cur, coll); canCreate = createAccount("Ryan", "1", cur, coll); canCreate = createAccount("Michael", "1", cur, coll); canCreate = createAccount("John", "1", cur, coll); canCreate = createAccount("Susan", "1", cur, coll); cur = coll.find(); printResults(cur, "Find All Records After Insert"); }//try catch(Exception e){ System.out.println(e); }//catch } (Note: This will eventually time out and quit) But when I run the same code on the computer running the database it's fine. How can I get a connection between two computers on different networks to communicate?
First you need to ensure a network route: can you ping computer b from computer a? can you telnet to the mongo port from the second computer to the first? If not, you have a networking problem not a programming one. In which case it might behoove you to ask this question on serverfault or superuser
Check if computer a can ping computer b. If it can, then check mongodb configuration parameters like auth and noauth and set the same according to your convinience.
Two computers on different networks? Because 192.168.0.102 sure looks like an internal address, not an external one. You need to figure out what's the public IP address of the computer running mongodb, and use that. What you're doing is almost like (but not quite as bad) as trying to connect to 127.0.0.1 and wondering why this only works when executed on the computer that hosts the service.
This is pretty much unrelated to MongoDB. Either your network connection is not working properly (firewall or routing issue) or your remote mongod daemon is not listening on the related external IP address (ensure that is bound to the proper IP address using the --bind_ip commandline option).