So I'm updating this as I've gotten JSON OUT however the JSON is followed by an INT
{"function":"timereport","values":545028}41
#include <ArduinoJson.h>
char owner[] = "";
const int capacity = JSON_OBJECT_SIZE(2);
DynamicJsonDocument doc(capacity);
void setup() {
Serial.begin(115200);
}
void loop() {
doc["function"]="timereport";
doc["values"]=millis();
Serial.println(serializeJson(doc, Serial));
delay(5000);
}
Second TRY:(Post Still has the INT at the end)
char json_string[256];
http.begin("http://192.168.1.103:2000/hydroapi"); //Specify destination for HTTP request
http.addHeader("Content-Type","application/json");
doc["function"]="timereport";
doc["values"]=millis();
serializeJson(doc, json_string);
int httpResponseCode = http.POST(json_string); //Send the actual POST request
http.end();
The call to serializeJson prints the json to Serial (as that's the stream your passing in) and returns the number of bytes printed, which you're then explicitly printing using Serial.println.
Remove the call to Serial.println to avoid printing the number of bytes, just call serializeJson(doc, Serial);
Related
I am trying to use my own UDF (written in c++) as a mysql extension. I was able to install the function via
CREATE FUNCTION decrypt RETURNS STRING SONAME "libudf_func.so";
and use it. I could also drop the function via
DROP FUNCTION decrypt;
After that it would not be listed in the mysql.func table, so Im pretty sure it was successfully deleted.
Now I want to use an updated version of my function, and therefore reload it in mysql. However, mysql only reloads the old version of my file (which I completely removed from the computer). Even if I remove ALL files named "libudf_func.so" it will be reloaded.
I'm using mysql version 8.0.28 for macos12.0 on localhost.
How can I remove this cached version or force mysql to reload?
EDIT
All my steps, from loading the first version to my attempt to load the updated version:
I used: CREATE FUNCTION decrypt RETURNS STRING SONAME "libudf.so"; to initially create the function decrypt
I changed something in my udf.cpp file.
I used: DROP FUNCTION decrypt; to remove the function decrypt
I used CREATE FUNCTION decrypt RETURNS STRING SONAME "libudf.so"; as an attempt to reload/refresh the function decrypt (NO ERRORS)
the behaviors did not change (among other things I wanted to output a different error message, so that was pretty obviously the old behavior)
I renamed libudf.so to lubudf_func.so
I replicated this with the new name.
I deleted ALL files with the names libudf.so or lubudf_func.so from my machine
I could still execute CREATE FUNCTION decrypt RETURNS STRING SONAME "libudf.so"; without any errors
I tried to call CREATE FUNCTION decrypt RETURNS STRING SONAME "libudf_xyz.so"; (never existed), which failed. Error message: "Error Code: 1126. Can't open shared library 'libudf_xyz.so' (errno: 2 dlopen(/usr/local/opt/mysql/lib/plugin/libudf_xyz.so, 0x0002): tried: '/usr/local/opt/mysql/lib/plugin/libudf_xyz.so' (no such f)"
plugin_dir: /usr/local/opt/mysql/lib/plugin/
--->(this is where the .so file WAS located, but is not anymore)
How did I notice the old behavior was still present? The dead giveaway was that the function used the old error message ("Please use plaintext(int), iv(string), key(string)"), and not the new message ("Please use plaintext(string), iv(string), key(string)") after step no. 4
Also add the content of the plugins/ directory, which CREATE FUNCTION uses to load the function: I wrote the library in c++, then built it as a shared library. The c++ code would be as follows (but Im not sure this is relevant):
extern "C" {
bool decrypt_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
char *decrypt(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);
void decrypt_deinit(UDF_INIT *initid);
}
bool decrypt_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
if (args->arg_count != 3 or
args->arg_type[0] != STRING_RESULT or
args->arg_type[1] != STRING_RESULT or
args->arg_type[2] != STRING_RESULT
) {
strcpy(message, "Usage: decrypt_poly(string ctext, string key, string iv)");
return 1;
}
if (args->lengths[2] != 48) {
strcpy(message, "Only 24-length IVs are allowed. Make sure IV is hexed.");
return 1;
}
initid->ptr = new char[args->lengths[0]];
initid->maybe_null = 1;
return 0;
}
char *decrypt(UDF_INIT *initid, UDF_ARGS *args,
char *result, unsigned long *length,
char *is_null, char *error) {
std::string dvalue;
if (NULL != args->args[0]) {
std::string value = std::string(args->args[0], args->lengths[0]);
std::string key = std::string(args->args[1], args->lengths[1]);
std::string iv = std::string(args->args[2], args->lengths[2]);
try {
dvalue = ((encryption::poly_based_encryption::decrypt(value, key, iv))));
}
catch (CryptoPP::Exception &e) {
std::cerr << e.what() << std::endl;
*error = 1;
}
} else {
dvalue = "";
*is_null = 1;
*error = 1;
return NULL;
}
strcpy(initid->ptr, dvalue.c_str());
*length = dvalue.length();
result = initid->ptr;
*is_null = 0;
*error = 0;
return result;
}
void decrypt_deinit(UDF_INIT *initid) {
if (initid->ptr)
delete[] initid->ptr;
}
I'm trying to use an ESP8266 and Arduino Uno to connect to wunderground and get the JSON file to get the current weather. With my code I am connecting to the server fine. What seems to be the issue is that it's not giving me the whole return file.
#include <SoftwareSerial.h>
#include <ArduinoJson.h>
SoftwareSerial esp8266(8, 9);
bool flag = true;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
esp8266.begin(9600);
}
void loop() {
if (flag) {
String cmd;
int length;
cmd = "AT+CIPSTART=\"TCP\",\"";
cmd += "api.wunderground.com";
cmd += "\",80";
esp8266.println(cmd);
Serial.println(cmd);
delay(2000);
Serial.write(esp8266.read());
if (esp8266.find("CONNECT")) {
Serial.println("CONNECT found so your connected");
}
String action;
action = "GET http://api.wunderground.com/api/APIKEY/conditions/q/Canada/Regina.json HTTP/1.0\r\n\r\n";
length = action.length();
cmd = "AT+CIPSEND=";
cmd += length;
esp8266.println(cmd);
Serial.println(cmd);
delay(5000);
if (esp8266.find(">")) {
Serial.print(">");
} else {
esp8266.println("AT+CIPCLOSE");
Serial.println(F("connect timeout"));
}
esp8266.println(action);
Serial.println(action);
delay(700);
String test = "";
while (esp8266.available()) {
char c = esp8266.read();
test += c;
}
Serial.println(test);
flag = false;
Serial.println("Flag is false");
}
}
Running this code give me the following result:
AT+CIPSTART="TCP","api.wunderground.com",80
ACONNECT found so your connected
AT+CIPSEND=97
GET http://api.wunderground.com/api/7287eb3ace065563/conditions/q/Canada/Regina.json HTTP/1.0
busy s...
Recv 97 bytes
SEND OK
+IPD,1460:HTTP/1.0:"0.1",
"termsofService":"http://www.wunderground.com/weather/api/d/terms.html",
"
Flag is false
As you can see I only get a snippet of the JSON file. I'm not sure what the problem is.
It's not sending JSON at all. It detected that your Arduino/ESP combo was not a human, and is scolding you, letting you know that you are in breach of the Terms of Service, as described in http://www.wunderground.com/weather/api/d/terms.html. You need to set some headers, to masquerade as a browser and thus pass as a human user.
I'm working on a student project and trying to send JSON data (based on the twitter hashtag '#tune') from Processing to Arduino, but the method 'myPort.write(status);' isn't usable with JSON, I've looked around online but not sure what command to use - Am I on the right track? Here's the code:
Processing:
import processing.serial.*; //Serial connection for Arduino
import java.lang.reflect.Method;
import com.temboo.core.*; // Temboo library
import com.temboo.Library.Twitter.Search.*; // Temboo Twitter search library
// Create a session using your Temboo account application details
TembooSession session = new TembooSession("MYUSERNAME", "MYTEMBOOAPPNAME", "MYTEMBOOCODE");
// Setup objects
Serial myPort; // Create object from Serial class
int portNo = 7; // Define portNo as int
int baudRate = 9600; // Define baudRate as int
void setup() {
// Run the Tweets Choreo function
runTweetsChoreo();
String portName = Serial.list()[portNo]; // Setup String for port ([7] is the port number for my machine)
myPort = new Serial(this, portName, baudRate); // Setting up serial port
}
void runTweetsChoreo() {
// Create the Choreo object using your Temboo session
Tweets tweetsChoreo = new Tweets(session);
// Set credential
tweetsChoreo.setCredential("ArduinoUkulele");
// Set inputs
// Run the Choreo and store the results
TweetsResultSet tweetsResults = tweetsChoreo.run();
// retrieve the results as JSON
JSONObject results = parseJSONObject(tweetsResults.getResponse());
// retrieve the statuses from the results
JSONArray statuses = results.getJSONArray("statuses");
// loop through the statuses
for (int i = 0; i < statuses.size(); i++){
JSONObject status = statuses.getJSONObject(i);
println(status.getString("text"));
println(" -- -- -- -- -- -- -- -- -- -- -- -- -- -- ");
myPort.write(status); // THIS IS THE CODE NOT WORKING WITH JSON
}
}
Arduino:
char val; // Data received from the serial port
int ledPin = 13; // Set the pin to digital I/O 13
void setup(){
pinMode(ledPin, OUTPUT); // Set pin as OUTPUT
Serial.begin(9600); // Start serial communication at 9600 bps
}
void loop(){
if (Serial.available()) { // If data is available to read,
val = Serial.read(); // read it and store it in val
Serial.println(val);
delay(10); // Wait 10 milliseconds for next reading
}
}
I'm sure I'm just looking for a certain command - once I've received the data I'm just looking to turn the LED on based on a new hashtag being receieved. Any help would be greatly appreciated!
Cheers
Arthur
write() method cannot take JSONObject as input, only byte[], String. But you already have everything you need: just use getString() method as you are doing it two lines above (using appropriate key string, which you should know from API that you are using on top of JSON):
myPort.write(status.getString("text"));
I have a mySQL database with hashed passwords that I cannot abandon. I need to duplicate the encrypt() function of mySQL so that I can be consistent in my hash creation for login in an iOS app I'm creating. (I'm using the first 2 characters of the password as the salt for the encrypt function)
Has anyone done this before? I tried to add the following category to NSString based on code I found elsewhere, but the resulting string isn't even close. (I have a base64 category on NSData and yes, I'm new to the CCCrypt call)
-(NSString*) encryptWithSalt:(NSString *)salt {
NSString *token = self;
const void *vplainText;
size_t plainTextBufferSize = [token length];
vplainText = (const void *) [token UTF8String];
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
bufferPtrSize = (plainTextBufferSize + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
uint8_t iv[kCCBlockSizeDES];
memset((void *) iv, 0x0, (size_t) sizeof(iv)); // zero out iv
const void *vkey = (const void *) [salt UTF8String];
ccStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding | kCCModeCBC,
vkey,
kCCKeySizeDES,
iv,
vplainText,
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
&movedBytes);
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
NSString* hash;
if (ccStatus == kCCSuccess) {
hash = [myData base64EncodedString];
}
return hash;
}
The crypt() function cannot be emulated using CCCrypt, as the salt is used to alter the DES E-box. This makes the cipher in use no longer really DES.
However, it's still just the crypt() function. Call it directly:
- (NSString*) encryptWithSalt:(NSString *)salt {
return [NSString stringWithUTF8String:crypt([self UTF8String], [salt UTF8String])];
}
Incidentally, using the first two characters of the password as the salt is a gigantic security hole, as it narrows the password search space down to six characters (because the first two are given away by the salt).
I have the below C struct that has a couple nested structures that have proven to be difficult to deal with using my knowledge of SWIG. Everything below is easily wrapped by SWIG execept for saddr (C socket address) and mac[6] (C array representing a MAC address). Since SWIG gives me the pointer value (SWIGTYPE_p_unsigned_char and SWIGTYPE_p_sockaddr), I would like to somehow call a helper C function to convert the pointer to a char*. I have the helper function, but I don't know the best way to plug this into SWIG. Is there any way to configure the getMac() and getSaddr() to call the helper function?
C Structure Trying To Wrap:
%rename (Details) details_t_;
typedef struct details_t_ {
uint16_t code;
char *name;
**sockaddr *saddr;**
uint32_t saddr_len;
uint8_t flag;
ios_boolean is_child;
**unsigned char mac[6];**
} details_t;
Generated Java Code:
public void setMac(SWIGTYPE_p_unsigned_char value) {
TestJNI.Details_mac_set(swigCPtr, this, SWIGTYPE_p_unsigned_char.getCPtr(value));
}
public SWIGTYPE_p_unsigned_char getMac() {
long cPtr = TestJNI.Details_mac_get(swigCPtr, this);
return (cPtr == 0) ? null : new SWIGTYPE_p_unsigned_char(cPtr, false);
}
public void setSaddr(SWIGTYPE_p_sockaddr value) {
TestJNI.Details_saddr_set(swigCPtr, this, SWIGTYPE_p_sockaddr.getCPtr(value));
}
public SWIGTYPE_p_sockaddr getSaddr() {
long cPtr = TestJNI.Details_saddr_get(swigCPtr, this);
return (cPtr == 0) ? null : new SWIGTYPE_p_sockaddr(cPtr, false);
}
Proposed SWIG.i Changes:
%module Test
%rename (realId) details_t_::mac;
%typemap(javacode) struct details_t_ %{
public String getMac() {
return Test.getMacAddressAsString(this);
//this is a pointer to details_t_ struct
}
%};
%rename (Details) details_t_;
typedef struct details_t_ {
uint16_t code;
char *name;
**sockaddr *saddr;**
uint32_t saddr_len;
uint8_t flag;
ios_boolean is_child;
**unsigned char mac[6];**
} details_t;
You can do this with a javacode typemap, e.g.:
%module test
%rename (realId) Sample::id;
%typemap(javacode) struct Sample %{
public byte getId() {
return 100-getRealId(); // Transform the real call
}
public void setId(byte value) {
setRealId(value+100);
}
%};
struct Sample {
char id;
};
Renames the generated getId() and setId(), but provides a Java get/set which can be written in terms of the SWIG generated (but renamed) one. You might want to make the SWIG generated ones private though.