How to define the variable in this handler correctly?

I’ve just finally started to take advantage of creating handlers myself. I’ve managed to convert most of my frequently repetitive things to subroutines just fine, but I’m having trouble with this one. It’s about sending commands to smart lights hub API using JSON.

I manage to get the preset handler to create a command string correctly, and (in isolation from that handler), successfully send commands to my lights using the following hue handler.
But if I try to run these two in a row, the script fails because “TestPreset” that I’m trying to have the handler use as a named variable for the preset, “has not been defined”.
I can see how it isn’t defined, but I can’t figure out how to have the handler also define it.
So hard to explain, hope I’m making some sense.

-----------------------------------------------------
# Hue preset making handler
-----------------------------------------------------
on huePreset(Preset, state, trans, hue, ct, bri, sat)
	set Preset to the quoted form of ("{\"on\": " & state & ", \"transitiontime\": " & trans & ", \"hue\": " & hue & ", \"ct\": " & ct & ", \"bri\": " & bri & ", \"sat\": " & sat & "}")
end huePreset

-----------------------------------------------------
# Hue send command handler
-----------------------------------------------------
on hue(setting, destination)
	do shell script "curl --request PUT --data " & setting & " " & destination
	delay 0.1
end hue


huePreset("TestPreset", true, "30", "20000", "", "254", "254") ---This creates the preset's name to be used as a variable in the next phase, and then the values to be passed onto the actual command string

hue(TestPreset, DestinationAddress) ---This takes the newly created setting called TestPreset and sends it to DestinationAddress


Without the handler, I used to create such presets this way:

set TestPreset to the quoted form of "{\"on\": true, \"transitiontime\": 30, \"hue\": 20000, \"ct\": , \"bri\": 254, \"sat\": 254}"

But it’s messy when you have plenty of them, they extend to the next row and the values are pretty annoying to edit.
The variables that you can enter into the command, by the way, are simply all the possible variables that can be sent; In reality, some are exclusive to specific lamp models only or I might not necessarily want to change every possible value in a single command, so the possibility to leave some values empty is intentional. In this case value ct is empty just to test that it’s still getting accepted.

Hi.

You need to set your TestPreset variable to the result from the huePreset() handler. In the handler itself, the Preset parameter you’ve specified isn’t used, so you can leave it out:

-----------------------------------------------------
# Hue preset making handler
-----------------------------------------------------
on huePreset(state, trans, hue, ct, bri, sat)
	return the quoted form of ("{\"on\": " & state & ", \"transitiontime\": " & trans & ", \"hue\": " & hue & ", \"ct\": " & ct & ", \"bri\": " & bri & ", \"sat\": " & sat & "}")
end huePreset

-----------------------------------------------------
# Hue send command handler
-----------------------------------------------------
on hue(setting, destination)
	do shell script "curl --request PUT --data " & setting & " " & destination
	delay 0.1
end hue


set TestPreset to huePreset(true, "30", "20000", "", "254", "254") ---This creates the preset's name to be used as a variable in the next phase, and then the values to be passed onto the actual command string

hue(TestPreset, DestinationAddress) ---This takes the newly created setting called TestPreset and sends it to DestinationAddress

Thanks Nigel, that does it!

I couldn’t figure out how to leave any which value empty if I wanted to, so I had to revise the handler one more time. Now I can choose what parameters to leave out if I so need. hue+sat and ct (color temperature) already are things that cancel one another out so in a command you can only ever have one or the other.
With the following handler, if I leave any value as empty “”, then that parameter command will be left out completely. :slight_smile:
Because after every thing there has to be a comma if there’s going to be more, for now I can’t be bothered to figure out how to give commands without including the state command; in this version, leaving it out would mean that the string starts with a command which is wrong. Would have to be some kind of logic where “if this is not the first item on the list, then start this line with a comma”.

-----------------------------------------------------
# Hue preset making handler (any preset except for state can be left empty))
-----------------------------------------------------
on huePreset(state, trans, hue, sat, bri, ct)
	set theLine to {}
	if state is not "" then
		copy "{\"on\": " & state to the end of theLine
	end if
	if trans is not "" then
		copy ", \"transitiontime\": " & trans to the end of theLine
	end if
	if hue is not "" then
		copy ", \"hue\": " & hue to the end of theLine
	end if
	if sat is not "" then
		copy ", \"sat\": " & sat to the end of theLine
	end if
	if bri is not "" then
		copy ", \"bri\": " & bri to the end of theLine
	end if
	if ct is not "" then
		copy ", \"ct\": " & ct to the end of theLine
	end if
	copy "}" to the end of theLine
	set theLine to theLine as string
	return the quoted form of theLine
end huePreset

…And as I was explaining that, I already had a feeling that I could just do it.
So this is the perfect version and uh, it seems a bit tedious! :o
Maybe I’ll only use this version where absolutely mandatory. I often do need to include the state:true command anyway.

-----------------------------------------------------
# Hue preset making handler (any parameter can be left empty)
-----------------------------------------------------
on huePreset(state, trans, hue, sat, bri, ct)
	set theLine to {}
	copy "{" to the end of theLine
	if state is not "" then
		if (count theLine) is 1 then --First item, don't start with comma
			copy "\"on\": " & state to the end of theLine
		else if (count theLine) > 1 then --Not the first item, start with comma
			copy ", \"on\": " & state to the end of theLine
		end if
	end if
	if trans is not "" then
		if (count theLine) is 1 then --First item, don't start with comma
			copy "\"transitiontime\": " & trans to the end of theLine
		else if (count theLine) > 1 then --Not the first item, start with comma
			copy ", \"transitiontime\": " & trans to the end of theLine
		end if
	end if
	if hue is not "" then
		if (count theLine) is 1 then --First item, don't start with comma
			copy "\"hue\": " & hue to the end of theLine
		else if (count theLine) > 1 then --Not the first item, start with comma
			copy ", \"hue\": " & hue to the end of theLine
		end if
	end if
	if sat is not "" then
		if (count theLine) is 1 then --First item, don't start with comma
			copy "\"sat\": " & sat to the end of theLine
		else if (count theLine) > 1 then --Not the first item, start with comma
			copy ", \"sat\": " & sat to the end of theLine
		end if
	end if
	if bri is not "" then
		if (count theLine) is 1 then --First item, don't start with comma
			copy "\"bri\": " & bri to the end of theLine
		else if (count theLine) > 1 then --Not the first item, start with comma
			copy ", \"bri\": " & bri to the end of theLine
		end if
	end if
	if ct is not "" then
		if (count theLine) is 1 then --First item, don't start with comma
			copy "\"ct\": " & ct to the end of theLine
		else if (count theLine) > 1 then --Not the first item, start with comma
			copy ", \"ct\": " & ct to the end of theLine
		end if
	end if
	copy "}" to the end of theLine
	set theLine to theLine as string
	return the quoted form of theLine
end huePreset

I recommend to download JSON Helper which is a faceless scriptable application like System Events.

Then you can create a JSON string from an AppleScript dictionary for example

on huePreset(jsonType)
	tell application "JSON Helper"
		return make JSON from jsonType
	end tell
end huePreset

set jsonString to huePreset({|on|:true, transitiontime:"30", hue:"20000", bri:"254", ct:"254"})

Yes, I’ve used JSON Helper for years, it’s great. However, with ASObjC, you no longer have to be reliant on an external application to handle JSON/AS Record conversion, it can be done directly. See Shane’s handlers here:
https://forum.latenightsw.com/t/applescript-record-to-json/668

Oh wow I actually have JSON Helper installed already, I’d just completely forgotten about it! I got it ages ago when I was getting acquainted with the whole JSON concept for the first time and wanted a quick workaround instead of having to learn the syntax all in one go. As I grew more knowledgeable, I forgot about the Helper even though it could still continue to be helpful in certain tasks.
Thanks, I’ll look into those options! Working on a big thing right now so I can’t dig into this right at this second but I’ll report back when it’s a good time.