Micropython Raspberry Pico interrupt but from which pin - micropython

What is the easiest way to know which pin caused the interrupt?
def handle_interrupt(Pin):
print(Pin)
int1 = Pin(2, Pin.IN,Pin.PULL_UP)
int1.irq(trigger=Pin.IRQ_FALLING, handler=handle_interrupt)
int2 = Pin(10, Pin.IN,Pin.PULL_UP)
int2.irq(trigger=Pin.IRQ_FALLING, handler=handle_interrupt)
the output is like this
Pin(2, mode=IN, pull=PULL_UP)
or
Pin(10, mode=IN, pull=PULL_UP)
I can use different handlers, or do all kind of crazy things like converting the class to a string and split etc etc but there has to be a easier way, right?

This seems to work:
def handle_interrupt(irq):
print(irq)
int1 = Pin(2, Pin.IN,Pin.PULL_UP)
int1.irq(trigger=Pin.IRQ_FALLING, handler=lambda a:handle_interrupt(2))
int2 = Pin(10, Pin.IN,Pin.PULL_UP)
int2.irq(trigger=Pin.IRQ_FALLING, handler=lambda a:handle_interrupt(10))

Related

Emonlib+ADS1115+ESP32+Arduino Function Pointer

I have tried to contact the original designer for the ADS1115->EmonLib adaptation, but unfortunately his Github page has no contact information. I have also tried asking on the OpenEnergyMonitor forum and I get "Contact the person who made the changes".
So, I've come here in the hopes that the knowledgeable folk here can help me out.
Situation:
I have an ESP32 that I'm going to be using to monitor my energy consumption of my home. Because I will be monitoring several circuits I need lots of sensors. The ESP32 only has a 12-bit ADC and I'm limited to only a few sensors. Also limits future expansion if needed.
So here comes the ADS1115, which is a 16-bit ADC, but it uses I2C. Unfortunately, the EmonLib was designed to use onboard ADC, and not through an I2C device. So after doing some digging around, I found this modification to allow the ADS1115 to be used:
https://github.com/PaulWieland/EmonLib/
However, Paul Wieland is not able to be contacted through github.
Ok, so if I wanted to use only 1 ADS1115, I could just use his code as stock, which is this:
// In this example we will use an ADS1115 breakout board instead of the Arduino's local analog inputs
// This is especially useful for nodemcu/esp8266 users who only have a single analog input
#include <Wire.h>
#include <Adafruit_ADS1015.h>
// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3
#include <EmonLib_I2C.h> // Include Emon Library
EnergyMonitor emon1; // Create an instance
Adafruit_ADS1115 ads; // Create an instance of the ADS1115 object
// Make a callback method for reading the pin value from the ADS instance
int ads1115PinReader(int _pin){
return ads.readADC_SingleEnded(_pin);
}
void setup()
{
emon1.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
emon1.current(1, 111.1); // Current: input pin, calibration.
}
void loop()
{
double Irms = emon1.calcIrms(1480); // Calculate Irms only
Serial.print(Irms*230.0); // Apparent power
Serial.print(" ");
Serial.println(Irms); // Irms
}
This compiles just fine. Though I am kinda confused as to how to select the "pin" of the ADS.
In the emonlib.cpp he added this code:
//--------------------------------------------------------------------------------------
// Constructor. Set the pinReader to the default pin reader method
//--------------------------------------------------------------------------------------
EnergyMonitor::EnergyMonitor()
{
this->inputPinReader = defaultInputPinReader;
}
//--------------------------------------------------------------------------------------
// By default we just call Arduino's analogRead
//--------------------------------------------------------------------------------------
int EnergyMonitor::defaultInputPinReader(int _pin)
{
return analogRead(_pin);
}
And changed this:
startV = analogRead(inPinV);
to:
startV = (this->inputPinReader)(inPinV);
and a few other spots where he made the adjustment using "this->".
And in the emonlib.h he added this to the Public section:
EnergyMonitor();
typedef int (*inputPinReaderMethod) (int _pin);
inputPinReaderMethod inputPinReader;
static int defaultInputPinReader(int _pin);
Now, for a single ADS1115, I think this works. At least the code compiles. But I need to use 4 ADS1115's as I'll need to be able to monitor up to 16 circuits. I can't for the life of me figure out how to add an array of ADS's to an array of emonlib's.
I tried doing this:
EnergyMonitor emon1[4]; // Create an instance
Adafruit_ADS1115 ads[4]; // Create an instance of the ADS1115 object
// Make a callback method for reading the pin value from the ADS instance
int ads1115PinReader(int _channel, int _pin){
return ads[1].readADC_SingleEnded(_pin);
}
void setup()
{
emon1[1].inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
emon1[1].current(1, 111.1); // Current: input pin, calibration.
}
void loop()
{
double Irms = emon1[1].calcIrms(1480); // Calculate Irms only
Serial.print(Irms*230.0); // Apparent power
Serial.print(" ");
Serial.println(Irms); // Irms
}
but then I get this error:
Emon_ADS_Test:18:27: error: invalid conversion from 'int (*)(int, int)' to 'EnergyMonitor::inputPinReaderMethod {aka int (*)(int)}' [-fpermissive]
emon1[1].inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
I'm not very advanced in coding, and function pointers just confuse the heck outta me.
So my dilemma is I have several ADS1115's I need to match to the several instances of the EmonLib.
There has to be a separate instance for each wire monitored. On my working model that uses an Arduino Nano I have 2 emonlib variables (emon1, emon2). This works fine as it uses the internal ADC, tho I've found out over time that it is not very accurate and not fast enough or high enough resolution for my needs. (ie. when 0-current is flowing, it shows 50W usage).
What do I need to make a change to make this thing work?
Kori
[UPDATE 1]
Ok, after some testing, I do still get this:
emon[i * j].inputPinReader = ads1115PinReader;
emon[i * j].current(j++, 111.1);
Unfortunately this throws an error still:
Emon_ADS_Test:21:33: error: invalid conversion from 'int (*)(int, int)' to 'EnergyMonitor::inputPinReaderMethod {aka int (*)(int)}' [-fpermissive]
emon1[i * j].inputPinReader = ads1115PinReader;
However, it comes to the function pointer as being a problem.
I use this code:
int ads1115PinReader(int _pin){
return ads.readADC_SingleEnded(_pin);
}
It works just fine. However if I do this:
int ads1115PinReader(int _channel, int _pin){
return ads[_channel].readADC_SingleEnded(_pin);
}
I get the error above. In the EmonLib_I2C library, the only thing I can think of is in this part:
typedef int (*inputPinReaderMethod) (int _pin);
inputPinReaderMethod inputPinReader;
static int defaultInputPinReader(int _pin);
not matching up. But even that doesn't make sense. In this line:
emon.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
does that mean that when I call inputPinReader, it "actually" grabs the value from ads1115PinReader instead of the one in the library?

Scala: how to get up to first n characters from a large string?

Using Scala, I am grabbing a json response object from a web API and storing the response as a string s. This string is at least several kilobytes. Because sometimes this response can provide some funky stuff hinting at errors or issues with the API I want to print out a preview of the response to our logs. That way I can see the log and tell that the job is either running successfully or has failed. Is there an efficient and safe way to grab the first 100 or so characters from a string? The string may occasionally be very small so grabbing via a slice I think will cause an index out of range issue.
val n = 100
val myString: String = getResponseAsString()//returns small or very large string
logger.warn(s"Data: $myString") //how to print only first 'n' chars?
"long string".take(4) // "long"
"x".take(4) // "x"
take
val n :Int = ...
val myString :String = ...
logger.warn(s"Data: %.${n}s" format myString)

nim language ,gintro demo with two columns in a listview / gtktreeview and sortable

For nim language there is only one gui toolkit working for me and that is gintro.
The democode listview compiles and runs nice on my netbsd.
Source:
http://ssalewski.de/gintroreadme.html
But I need a listview(gtktreeview) with two columns, I looked into nim.gtk but can't figure out which "casts" I should spell.
The code in the demo program:
let gtype = typeFromName("gchararray")
let store = newListStore(N_COLUMNS, cast[pointer]( unsafeaddr gtype))
# cast due to bug in gtk.nim
Works nice for N_COLUMNS=1 but not N_COLUMNS:2
Here is the relevant part in nim.gtk:
proc newListStore*(nColumns: int; types: GTypeArray): ListStore =
let gobj = gtk_list_store_newv(int32(nColumns), types)
Second when I have multiple colums I would like to make it sortable by clicking on the header (like an excel table)
I think you need something like this:
let gtypes = [typeFromName("gchararray"), typeFromName("gchararray")] # Be sure to change the types to whatever you need.
let store = newListStore(N_COLUMNS, addr gtype[0]) # You shouldn't need this weird cast here.
Untested but should work. Feel free to join our Gitter/IRC if you need more help :)

How to use an array in Pony?

Since the documentation and tutorials on collections in Ponylang are lacking, I'm really struggling in using the Array class and working with indices.
I have an overenginered actor-based fizzbuzz where there's an actor in charge of requesting fizzbuzz operations to other actors and collecting the results. Probably the pattern I'm using is not the best but right now I would like to iterate in this way to learn more.
My problem is with the following code:
actor FizzBuzzer
var _results:Array[String]
let _main: Main tag
fun list_to_string(l:List[String]):String=>
l.fold[String]({(a:String,b:String)=>a+"\n"+b},"")
new create(n:String, main:Main tag)=>
let num:USize = try (consume n).usize()? else 0 end
_main = main
_results = recover Array[String] end
try
let result = this.fizzbuzz(num)?
let message:String = list_to_string(result)
main.print(message)
else
main.print("Invalid argument: "+ num.string())
end
fun fizzbuzz(n:USize, acc:List[String]=List[String]()):List[String] ?=>
if n <=0 then error end
let res = List[String]()
for i in Range[USize](1,n+1) do
FizzBuzzerino.process(i,this)
end
res
be collect_result(result:String,num:USize)=>
try
_results.insert(num,result)?
else
_main.print("Error processing element: "+num.string())
end
`
In the function collect_result the insertion always fails. Using update is the same. The result and num I receive from the processing actor are correct but I cannot insert them in the array. Any insertion in the Array in this class fails. Is it a matter of capabilities? Or am I doing something wrong?

Erlang variable pattern matching

I have a service_echo function in a simple chat application which uses SockJS for implementing multi-user private chat. I created an ETS table for the list of online users. By storing SockJS session, I thought to send message to that Connection whenever I receive a message from a different Connection.
Here is my service_echo code.
service_echo(Conn, {recv, Data}, state) ->
Obj = mochijson2:decode(Data),
{struct, JsonData} = Obj,
Name = proplists:get_value(<<"name">>, JsonData),
A = ets:lookup(username,Name),
io:format("~p",[Conn]),
if
length(A) =:= 0 ->
ets:insert(username,{Name,Conn});
true ->
[{AA,BB}] = ets:lookup(username,Name),
BB:send(Data)
end,
io:format("hello");
Even though Conn and BB are same, still Conn:send(data) sends a valid data to the browser while BB:send(Data) does nothing and even does not show an error.
Since I'm a new to Erlang, please excuse me for any unintented mistakes.
First of all, let me advise you on never using length(A) =:= 0 for testing whether the list A is empty or not; if A a long list, counting its elements will cost you a lot, although the result will not actually be used. Use A =:= [] instead, simpler and better.
I don't understand why you're saying that Conn and BB are the same. This does not follow from the code that you have posted here. If Name is not in the table, you insert an entry {Name, Conn}. Otherwise, if Name exists in the table and is related to a single object BB, you assume that this BB is a module and you call the send function defined therein.
It could be that you're reading wrong the semantics of if --- if that's the case, don't let the true guard confuse you, this is how an if-then-else is written in Erlang. Maybe you wanted to have something like:
...
A = ets:lookup(username,Name),
if
A =:= [] ->
ets:insert(username,{Name,Conn})
end,
[{_,BB}] = ets:lookup(username,Name),
BB:send(Data)
...
or even better:
...
A = ets:lookup(T,Name),
if
A =:= [] ->
ets:insert(T,{Name,Conn}),
BB = Conn;
true ->
[{_,BB}] = A
end,
BB:send(Data)
...
On the other hand, it could be that I misunderstood what you're trying to do. If that's the case, please clarify.