I have a Bluetooth LE module on Arduino which sends a JSON string to an Android application.
The JSON string look like this:
{'d_stats':[{'t':'26.62','h':'59.64','p':'755.23','a':'109.02','hrm':'0.00'}]}
The Android app receives packets of 20 bytes (20 characters limit) and I can't find a method to put all packets together when the last packet was received.
Is there a way to know when the last packet is received?
Edit: the bluetooth sends data at a constant interval of time. There is a button connected to the Arduino board which, when pushed, will send other data via Bluetooth. The problem is that it overlaps with the timed transmission.
I found the solution, although not very elegant.
Instead of sending the whole JSON string, BLE will send a key/value pair in a single packet.
In C first:
char passMsg(String akey, char* origMsg){
// akey = object key must be 4 characters long
// origMsg + akey must be shorter than 20 characters
char* newmsg = origMsg;
size_t prevlen = strlen(newmsg);
memset(newmsg + prevlen, ' ', 15 - prevlen);
*(newmsg + 15) = '\0';
String bleMsg = akey + ":"+newmsg;
ble.print("AT+BLEUARTTX=");
ble.println(bleMsg);
}
This way I pass a string like this: temp:20.45
Then in Android/Java:
String[] rawString = data.replace(" ", "").split(":");
if(rawString.length>1){
String apiCallKey = rawString[0];
String apiCallVal = rawString[1];
callAPI(apiCallKey,apiCallVal);
}
Where data is raw data from Bluetooth.
Phew...
Related
I have written an application on Android which realises sending simply requests (using Volley) to the server. The server is stood up on the NodeMCU (ESP8266) microcontroller, written in Lua. The problem is, that after sending the request, application not always is able to print the response. If the address is e.g. "http://www.google.com" it correctly sends request and receive and display response, but if it is the address from the code below - it correctly sends request (the server reacts) but does not (?) receive response (does not display it, displays: "That didn't work!"). Do you have any ideas, how can I fix it and be able to print the response?
Android (part responsible for sending requests):
buttonSynchro.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Instantiate the RequestQueue.
String url = "http://192.168.1.12/";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
testTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
testTextView.setText("That didn't work!");
}
});
// Add the request to the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(SettingsActivity.this);
queue.add(stringRequest);
}
});
NodeMCU, Lua:
station_cfg={}
station_cfg.ssid="Dom"
station_cfg.pwd="lalala"
wifi.sta.config(station_cfg)
function receive(conn, request)
print(request)
print()
local buf = "";
buf = buf.."<!doctype html><html>";
buf = buf.."<h1> ESP8266 Web Server</h1>";
buf = buf.."</html>";
conn:send(buf);
conn:on("sent", function(sck) sck:close() end);
collectgarbage();
end
function connection(conn)
conn:on("receive", receive)
end
srv=net.createServer(net.TCP, 30)
srv:listen(80, connection)
The code by nPn works in some user agents (Chrome/Firfox/curl/wget on macOS) but not in others (Safari on macOS & iOS, Firefox Klar on iOS). That likely is due to missing HTTP headers.
I advise you stick to the example we have in our documentation at https://nodemcu.readthedocs.io/en/latest/en/modules/net/#netsocketsend.
srv = net.createServer(net.TCP)
function receiver(sck, data)
print(data)
print()
-- if you're sending back HTML over HTTP you'll want something like this instead
local response = {"HTTP/1.0 200 OK\r\nServer: NodeMCU on ESP8266\r\nContent-Type: text/html\r\n\r\n"}
response[#response + 1] = "<!doctype html><html>"
response[#response + 1] = "<h1> ESP8266 Web Server</h1>"
response[#response + 1] = "</html>"
-- sends and removes the first element from the 'response' table
local function send(localSocket)
if #response > 0 then
localSocket:send(table.remove(response, 1))
else
localSocket:close()
response = nil
end
end
-- triggers the send() function again once the first chunk of data was sent
sck:on("sent", send)
send(sck)
end
srv:listen(80, function(conn)
conn:on("receive", receiver)
end)
Also, your code (and nPn's for that matter) makes assumptions about WiFi being available where it shouldn't.
wifi.sta.config(station_cfg) (with auto-connect=true) and wifi.stat.connect are asynchronous and thus non-blocking - as are many other NodeMCU APIs. Hence, you should put the above code into a function and only call it once the device is connected to the AP and got an IP. You do that by e.g. registering a callback for the STA_GOT_IP event with the WiFi event monitor. You'll find a very elaborate example of a boot sequence that listens to all WiFi events at https://nodemcu.readthedocs.io/en/latest/en/upload/#initlua. For starters you may want to trim this and only listen for got-IP.
Based on your comment above and the link you posted showing the traceback, your android app is crashing in the onResponse() method because you are asking for a substring longer than the actual string length.
You can fix this in a number of ways, but one would be to make the ending index be the minimum of the length of the response and 500 (which I assume is the max you can take in your TextView?). You can try changing
testTextView.setText("Response is: "+ response.substring(0,500));
to
testTextView.setText("Response is: "+ response.substring(0, Math.min(response.length(), n)));
or whatever other way you think is more appropriate to limit the length of the response that does not cause the IndexOutOfBoundsException
See the substring method here
public String substring(int beginIndex,
int endIndex)
Returns a new string that is a substring of this string. The substring
begins at the specified beginIndex and extends to the character at
index endIndex - 1. Thus the length of the substring is
endIndex-beginIndex.
Examples:
"hamburger".substring(4, 8) returns "urge"
"smiles".substring(1, 5) returns "mile"
Parameters:
beginIndex - the beginning index, inclusive.
endIndex - the ending index, exclusive. Returns:
the specified substring. Throws:
IndexOutOfBoundsException - if the beginIndex is negative, or endIndex is larger than the length of this String object, or
beginIndex is larger than endIndex.
I am not a Lua expert, but I think you are registering your "sent" callback after you send the response.
I think you should move it into the connection function:
station_cfg={}
station_cfg.ssid="Dom"
station_cfg.pwd="lalala"
wifi.sta.config(station_cfg)
function receive(conn, request)
print(request)
print()
local buf = "";
buf = buf.."<!doctype html><html>";
buf = buf.."<h1> ESP8266 Web Server</h1>";
buf = buf.."</html>";
conn:send(buf);
collectgarbage();
end
function connection(conn)
conn:on("receive", receive)
conn:on("sent", function(sck) sck:close() end);
end
srv=net.createServer(net.TCP, 30)
srv:listen(80, connection)
I have CloudHopper SMPP server, at this moment I can receive a simple short messages.
if (pduRequest.getCommandId() == SmppConstants.CMD_ID_SUBMIT_SM) {
SubmitSm request = (SubmitSm) pduRequest;
request.getShortMessage();
....
}
But what I should do to receive long (Multipart) message?
I don't know what object I have to use ...
Help me, please.
Many thanks.
The following processes a multipart long message PDU that you would get when receiving a long message that has been split into multiple PDUs:
import com.cloudhopper.commons.charset.GSMCharset;
import com.cloudhopper.commons.gsm.GsmUtil;
import com.cloudhopper.smpp.pdu.DeliverSm;
import com.cloudhopper.smpp.util.SmppUtil;
...
DeliverSm mobileOriginatedMessage = (DeliverSm) pduRequest;
boolean isUdh = SmppUtil.isUserDataHeaderIndicatorEnabled(mobileOriginatedMessage.getEsmClass());
if (isUdh) {
byte[] userDataHeader = GsmUtil.getShortMessageUserDataHeader(messageBytes);
int thisMessageId = userDataHeader[3] & 0xff;
int totalMessages = userDataHeader[4] & 0xff;
int currentMessageNum = userDataHeader[5] & 0xff;
messageBytes = GsmUtil.getShortMessageUserData(messageBytes);
GSMCharset gsmCharset = new GSMCharset();
String message = gsmCharset.decode(messageBytes); // Example decoding, depends on charset used
System.out.println("thisMessageId: " + thisMessageId); // unique to message, same across all message parts
System.out.println("totalMessages: " + totalMessages);
System.out.println("currentMessageNum: " + currentMessageNum);
System.out.println("Message: " + message);
}
...
The above shows how to:
Determine if a PDU is multipart long (UDH) message
Get all the UDH header information so you can know
what message the part belongs to
what part number was received in order to put the message back together in the right order
and what the total number of parts you are expecting is
Get the actual message text of each part
i'm developing sniffer in java with eclipse . i can sniff HTTP packet, TCP , UDP . But i need to control or ''state'' if request limit more than 10 in one second. İ know with jnetpcap we can't block , i just want to know it is possible i can get this. Thank you . Below my code
PcapPacketHandler <String> jpacketHandler = new PcapPacketHandler<String> ()
{
private final Http h = new Http();
private final Tcp t = new Tcp();
#Override
public void nextPacket(PcapPacket packet, String user) {
if(packet.hasHeader(h)){
final JCaptureHeader header = packet.getCaptureHeader();
System.out.printf("---------1111--------" + header.toString()+ "-------1111--------");
System.out.printf("packet caplen= %d wiredlen = %d \n ",
header.caplen(),header.wirelen());
System.out.println(packet.toString());
// System.out.printf("---------+++++++++--------" + packet.getHeader(h).toString() + "-------++++++--------");
//packet.getHeader(h).toString();
//Find if the given packet is a Request/Response Pkt : First get the TCP header
packet.getHeader(t);
}
I'm experimenting with java flavored zmq to test the benefits of using PGM over TCP in my project. So I changed the weather example, from the zmq guide, to use the epgm transport.
Everything compiles and runs, but nothing is being sent or received. If I change the transport back to TCP, the server receives the messages sent from the client and I get the console output I'm expecting.
So, what are the requirements for using PGM? I changed the string, that I'm passing to the bind and connect methods, to follow the zmq api for zmq_pgm: "transport://interface;multicast address:port". That didn't work. I get and invalid argument error whenever I attempt to use this format. So, I simplified it by dropping the interface and semicolon which "works", but I'm not getting any results.
I haven't been able to find a jzmq example that uses pgm/epgm and the api documentation for the java binding does not define the appropriate string format for an endpoint passed to bind or connect. So what am I missing here? Do I have to use different hosts for the client and the server?
One thing of note is that I'm running my code on a VirtualBox VM (Ubuntu 14.04/OSX Mavericks host). I'm not sure if that has anything to do with the issue I'm currently facing.
Server:
public class wuserver {
public static void main (String[] args) throws Exception {
// Prepare our context and publisher
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket publisher = context.socket(ZMQ.PUB);
publisher.bind("epgm://xx.x.x.xx:5556");
publisher.bind("ipc://weather");
// Initialize random number generator
Random srandom = new Random(System.currentTimeMillis());
while (!Thread.currentThread ().isInterrupted ()) {
// Get values that will fool the boss
int zipcode, temperature, relhumidity;
zipcode = 10000 + srandom.nextInt(10000) ;
temperature = srandom.nextInt(215) - 80 + 1;
relhumidity = srandom.nextInt(50) + 10 + 1;
// Send message to all subscribers
String update = String.format("%05d %d %d", zipcode, temperature, relhumidity);
publisher.send(update, 0);
}
publisher.close ();
context.term ();
}
}
Client:
public class wuclient {
public static void main (String[] args) {
ZMQ.Context context = ZMQ.context(1);
// Socket to talk to server
System.out.println("Collecting updates from weather server");
ZMQ.Socket subscriber = context.socket(ZMQ.SUB);
//subscriber.connect("tcp://localhost:5556");
subscriber.connect("epgm://xx.x.x.xx:5556");
// Subscribe to zipcode, default is NYC, 10001
String filter = (args.length > 0) ? args[0] : "10001 ";
subscriber.subscribe(filter.getBytes());
// Process 100 updates
int update_nbr;
long total_temp = 0;
for (update_nbr = 0; update_nbr < 100; update_nbr++) {
// Use trim to remove the tailing '0' character
String string = subscriber.recvStr(0).trim();
StringTokenizer sscanf = new StringTokenizer(string, " ");
int zipcode = Integer.valueOf(sscanf.nextToken());
int temperature = Integer.valueOf(sscanf.nextToken());
int relhumidity = Integer.valueOf(sscanf.nextToken());
total_temp += temperature;
}
System.out.println("Average temperature for zipcode '"
+ filter + "' was " + (int) (total_temp / update_nbr));
subscriber.close();
context.term();
}
}
There are a couple possibilities:
You need to make sure ZMQ is compiled with the --with-pgm option: see here - but this doesn't appear to be your issue if you're not seeing "protocol not supported"
Using raw pgm requires root privileges because it requires the ability to create raw sockets... but epgm doesn't require that, so it shouldn't be your issue either (I only bring it up because you use the term "pgm/epgm", and you should be aware that they are not equally available in all situations)
What actually appears to be the problem in your case is that pgm/epgm requires support along the network path. In theory, it requires support out to your router, so your application can send a single message and have your router send out multiple messages to each client, but if your server is aware enough, it can probably send out multiple messages immediately and bypass this router support. The problem is, as you correctly guessed, trying to do this all on one host is not supported.
So, you need different hosts for client and server.
Another bit to be aware of is that some virtualization environments--RHEV/Ovirt and libvirt/KVM with the mac_filter option enabled come to mind-- that, by default, neuter one's abilities via (eb|ip)tables to utilize mcast between guests. With libvirt, of course, the solution is to simply set the option to '0' and restart libvirtd. RHEV/Ovirt require a custom plugin.
At any rate, I would suggest putting a sniffer on the network devices on each system you are using and watching to be sure traffic that is exiting the one host is actually visible on the other.
Has anyone implemented a mod_auth_tkt cookie generation using Java?
I'm stuck on how to generate the iptstamp (can be done in PHP using the pack function) and hextimestamp in Java.
The algorithm for generating the cookie is below:
cookie := digest + hextimestamp + user_id + '!' + token_list + '!' + user_data
digest := MD5(digest0 + key)
digest0 := MD5(iptstamp + key + user_id + '\0' + token_list + '\0' + user_data)
iptstamp is a 8 bytes long byte array, bytes 0-3 are filled with client's IP address as a binary number in network byte order, bytes 4-7 are filled with timestamp as a binary number in network byte order.
hextimestamp is 8 character long hexadecimal number expressing timestamp used in iptstamp.
token_list is an optional comma-separated list of access tokens for this user.
This list is checked if TKTAuthToken is set for a particular area.
user_data is optional
Simply convert the IP Address to 4 bytes and append the timestamp.
iptstamp = ip_chars + ts_chars
http://code.cmlenz.net/diva/changeset/173/branches
http://www.mail-archive.com/modauthtkt-users#lists.sourceforge.net/msg00003.html
Using the following to get network byte order.
ByteBuffer bb = ByteBuffer.allocate(4096);
bb.order(ByteOrder.BIG_ENDIAN);
See
Network Order short (Java)