NEW DOCUMENTATION! Hints and Tips

I’ve introduced a Hints and Tips section to the Dev Center, part of the new Troubleshooting section. It’ll be home to a growing number of short blocks of code and advice for dealing with specific situations and performing key tasks on imp-based devices and their agents. Things like scanning for connected devices’ I²C addresses, converting hexadecimal strings to integers and back, how to load large blocks of data via HTTP, signal a successful code update and more.

If you have any hints and tips you’d like to share, you can send me a direct message, or post them here. I’ll add them to the Dev Center (with a credit) so they are available to the wider imp developer community.

Thanks for the addition of this section!

As for “Convert an Object’s Name to a Reference” - I’ve implemented this in my code as well, but thought the following might help clarify a few things.

First, it seems like there is a pathArray = split(pathString, ".") missing somewhere, or at least it seems like it should be happening outside of the function call, but it maybe helpful to include as the example states “if the string is ‘myclass.mytable.myelement’, the function will return a reference…”.

Second, it is extremely important to note that this function, in its current implementation, will not always return a reference, but will return the element at that location. If that element happens to be a reference, such as in the case of a table, the elements of that table can be altered, but simply replacing the table will have no effect.

For example, imagine I had a table structured as the following:

mytable: { mystring: "my string", mynumber: 5, mynestedtable: { a: "regular table" } }

The following code would produce the resulting output:

`
local stringRef = resolveReference(“mytable.mystring”);
stringRef = “my new string”;
server.log(resolveReference(“mytable.mystring”) //prints “my string”

local numRef = resolveReference(“mytable.mynumber”);
numRef = 10;
server.log(resolveReference(“mytable.mynumber”) //prints 5

local nestedTableRef = resolveReference(“mytable.mynestedtable”);
nestedTableRef = { a: "totally new table };
server.log(resolveReference(“mytable.mynestedtable.a”) //prints “regular table”

nestedTableRef.a = "totally newer table"
server.log(resolveReference(“mytable.mynestedtable.a”) //prints “totally newer table”
`

The function works great for resolving the element at the provided location, so it is great for reading data. It is also great for writing data if and only if the element is a table, and you want to alter the elements in the table itself, but one cannot expect the element to change by just overwriting the return value of the function.

Now all of this can be easily solved without changing the function, but the above code would have to be altered to the following:

`
local tableRef = resolveReference(“mytable”);

tableRef.mystring <- “my new string”; //need to use “<-” in case the nested element doesn’t exist
server.log(resolveReference(“mytable.mystring”) //prints “my new string”

tableRef.mynumber <- 10;
server.log(resolveReference(“mytable.mynumber”) //prints 10

tableRef.mynestedtable <- { a: "totally new table };
server.log(resolveReference(“mytable.mynestedtable.a”) //prints “totally new table”
`

Essentially, one must use the function to traverse to the containing table to alter the elements in place.

Hopefully that was helpful rather than confusing!

Also, I recently learned that Squirrel does not have a simple method to find the last occurrence of a substring within a string (at least, I haven’t come across one).

I’ve created the following function to accomplish that functionality:
`
function lastIndexOf(string, substr){
local tmp = string.find(substr);
if (tmp == null) return tmp;

local lastIdx = 0;
while (1){
    tmp = string.find(substr, lastIdx+1)
    if (tmp) lastIdx += tmp
    else break;
}
return lastIdx;

}
`
It’s not very pretty (I think there could be better ways to write it), but it covers some edge cases, including if the string only has one occurrence of the substring at index zero, and if the substring doesn’t exist at all (in which case the function returns null).

This, in tandem with my last post, helps to create a wrapper function for writing to a reference by obtaining the reference to the parent element:

function writeToReference(ref, value){ local pathArray = split(ref, "."); if (pathArray.len() == 1){ //write to reference how you see fit } else { local lastElem = pathArray.remove(pathArray.len()-1); local parentRefStr = ref.slice(0, lastIndexOf(ref, ".")) //removes the last element from string local parentRef = resolveReference(parentRefStr); parentRef[lastElem] <- value; } }

And, while we’re at it, I made a few alterations to the resolveReference function to add a little bit of functionality:
`
//Takes a string using standard dot notation and resolves to an object reference
//For example, “myclass.mytable.myelement” will resolve to the object “myelement”, if it exists
//If createPath is set to true, the function will create a blank table at each level of traversing through the pathArray
function resolveReference(pathString, object=this, createPath=false)
{
local pathArray = split(pathString, “.”);
//local object = this;

foreach (element in pathArray)
{
    if (element in object)
    {
        object = object[element];
    }
    else
    {
        if (createPath){
            object[element] <- {};
            object = object[element];
        }
        else return null
    }
}

return object

}
`

The first argument is the path string expressed in standard dot notation (now this function does the splitting).

The second argument allows for, instead of always defaulting to the scope of what calls this function, one can specify the object to search through.

Finally, the third argument is really just for using this function to resolve a reference to write a key-value pair to (as mentioned in my posts above). If set to true, and an element doesn’t exist in the object, it will create a blank table at that location so the function can continue traversing.

Thanks for the update, @mmuelle4 - I’ll update accordingly.

The regexp method regexp.capture() can be used to generate a table listing all the occurrences of the search string within another string.

FYI… there is a small typo in the code under
"Hardware" > “Display the WiFi Signal Strength Where the imp is Placed”

http://electricimp.com/docs/troubleshooting/tips/wifisignal/

The bracket just above the last else statement is the wrong direction.