Difference between revisions of "InfoCenter"

Line 79: Line 79:
 
==Updates & Release Notes==
 
==Updates & Release Notes==
 
You can update any InfoCenter product by rezzing it directly from your inventory (each one has an updater script which auto-deletes on first rez, so rezzing a used copy will not work).
 
You can update any InfoCenter product by rezzing it directly from your inventory (each one has an updater script which auto-deletes on first rez, so rezzing a used copy will not work).
 +
* '''v3.2'''
 +
** Added JSON API (backwards-compatible with earlier versions).
 +
** Improved font.
 +
** Fixed bug where graphic frame would be displayed at the same time as rendering text.
 
* '''v3.1'''
 
* '''v3.1'''
 
** Added chat API.
 
** Added chat API.
Line 87: Line 91:
 
==API Documentation==
 
==API Documentation==
 
For the legacy API, [[InfoCenter v3 Legacy API|see here]].
 
For the legacy API, [[InfoCenter v3 Legacy API|see here]].
 +
 +
The InfoCenter signs are controllable using an HTTP/JSON API. This can be used from LSL or from any software or server capable of forming JSON strings and sending HTTP requests.
 +
 +
A sample JSON request is as follows:
 +
 +
{
 +
"request": "set_text",
 +
"api_key": "1234567890123456",
 +
"frames": [
 +
{
 +
"text": "Hello World!",
 +
"color": "",
 +
"align": "center",
 +
"word_wrap": true,
 +
"ignore_length": true,
 +
"time": 3
 +
},
 +
{
 +
"lines": [
 +
{
 +
"text": "ABCDEFGHIJKLMNOP",
 +
"color": "ROAYGBPWROAYGBPW",
 +
"align": "left"
 +
},
 +
{
 +
"text": "^^^^^^^^^^^^^^^^",
 +
"align": "right"
 +
}
 +
],
 +
"ignore_length": true,
 +
"time": 3
 +
},
 +
{
 +
"graphic": "Stop",
 +
"time": 3
 +
}
 +
]
 +
}
 +
 +
===Required Key/Values===
 +
The JSON request must be an object with the following key-value pairs:
 +
 +
* '''request''': Must be "set_text".
 +
* '''api_key''': The API key of the display or group to set.
 +
* '''frames''': An array of objects, each object being a single frame.
 +
 +
===Frame Object===
 +
Each frame must have only one of these required key-value pairs:
 +
 +
* '''text''': A string of text to display.
 +
* '''lines''': An array of objects, each object being a single line on the display. Allows more precision in where text is displayed.
 +
* '''graphic''': The name of a graphic supported by this display (see below).
 +
 +
The key-value above used determines which type of frame it is, which determines which options are available.
 +
 +
====Text Frame Type====
 +
A '''text''' frame type can have the following options:
 +
 +
* '''text''': Required. A string of text to display.
 +
* '''color''': Optional. A color string (see below). If an empty string or not defined, "A" is used.
 +
** If the color string is shorter than the text string, the rest of the text uses the last color character.
 +
** If '''word_wrap''' is enabled, the entire frame will only be the color of the last color character due to technical limitations.
 +
* '''align''': Optional. Either "left", "center", or "right". Can also be "l", "c", or "r". If not defined, aligned to left.
 +
** If '''word_wrap''' is enabled, this will align each line. If it is disabled, this will only align the last line, because the lines before it (if any) will be the full width of the display.
 +
* '''word_wrap''': Optional. Must be true to enable (JSON_TRUE in LSL). If enabled, words are wrapped naturally. If disabled or not defined, text is "hard" wrapped to the full width of the display. It is a good idea to enable '''ignore_length''' to avoid errors if words wrap beyond the limits of the display.
 +
* '''ignore_length''': Optional. Must be true to enable (JSON_TRUE in LSL). If enabled, the server will not check the length of the text. If disabled or not defined, the server will return an error if the text exceeds the maximum the display can show.
 +
* '''time''': Optional. A length of time in seconds, between 1 and 3600, to display the frame. If not defined, the time will default to 5 seconds.
 +
** The server does not check the minimum time it would take to render the display, so very short frame times may produce unintended results.
 +
 +
====Lines Frame Type====
 +
A '''lines''' frame type can have the following options:
 +
 +
* '''lines''': Required. An array of objects, each object being a single line on the display. Allows more precision in where text is displayed. Each line can have the following options:
 +
** '''text''': Required. A string of text to display on the line.
 +
** '''color''': Optional. Optional. A color string (see below). If the color string is shorter than the text string, the rest of the text uses the last color character. If the '''color''' option is not defined or is empty, "A" is used. If an invalid character is used, it is replaced with "W".
 +
** '''align''': Optional. Either "left", "center", or "right". Can also be "l", "c", or "r". If not defined, aligned to left.
 +
* '''ignore_length''': Optional. Must be true to enable (JSON_TRUE in LSL). If enabled, the server will not check the length of the text on each line, nor will it check the number of lines included in the request. If disabled or not defined, the server will return an error if the text exceeds the maximum the display can show in either dimension.
 +
* '''time''': Optional. A length of time in seconds, between 1 and 3600, to display the frame. If not defined, the time will default to 5 seconds.
 +
** The server does not check the minimum time it would take to render the display, so very short frame times may produce unintended results.
 +
 +
====Graphic Frame Type====
 +
A '''graphic''' frame type can have the following options:
 +
 +
* '''graphic''': The name of a graphic supported by this display. This is case-insensitive, but must otherwise be an exact match to a supported graphic, or the server will return an error. The supported graphics are as follows:
 +
** ''InfoCenter Highway'': "Stop", "Hazard", "Do Not Enter"
 +
** ''InfoCenter Matrix'': "Stop", "Hazard", "Do Not Enter", "Detour Left", "Detour Right", "Lane Open Down", "Lane Open Up", "Lane Closed", "Lane Left Down", "Lane Right Down", "Lane Left Up", "Lane Right Up", "One Way Left", "One Way Right", "Yield", "Do Not Pass", "Stay In Lane", "No Trucks", "Trucks OK", "Speed Limit 5", "Speed Limit 10", "Speed Limit 15", "Speed Limit 20", "Speed Limit 25", "Speed Limit 30", "Speed Limit 35", "Speed Limit 40", "Speed Limit 45", "Speed Limit 50", "Speed Limit 55", "Speed Limit 60", "Speed Limit 65", "Speed Limit 70", "Speed Limit 75", "Speed Limit 80", "Keep Right", "Keep Left", "No Right Turn", "No Left/U Turn", "No Left Turn", "No U Turn", "Straight Or Left", "Straight Or Right", "Straight Only", "Left Turn Only", "Right Turn Only", "No Turns"
 +
** ''InfoCenter Notice'': "Information", "Today's Events", "Huge Sale", "Discounts", "Best Deals", "Notice", "Warning", "Danger"
 +
** ''InfoCenter Personal'': "Sale", "Come On In", "News Flash", "Happy 4th", "Welcome", "Open", "Closed", "Thank You", "No Smoking"
 +
** ''InfoCenter Mobile'': "Stop", "Hazard", "Do Not Enter", "Chase Right", "Chase Left", "Arrow Right", "Arrow Left", "Flash Right", "Flash Left", "Chevron Right", "Chevron Left", "Arrow Split", "Flash Split", "Flagger", "Stop Left", "Stop Right", "Detour Left", "Detour Right"
 +
* '''time''': Optional. A length of time in seconds, between 1 and 3600, to display the frame. If not defined, the time will default to 5 seconds.
 +
 +
===HTTP Request Format===
 +
The required URL, as part of an LSL HTTP request, is as follows:
 +
 +
llHTTPRequest("http://ntbigroup.com/gentek/infocenter/api_json.php", [HTTP_METHOD, "PUT"], json_request);
 +
 +
This URL is also accessible from any web server.
 +
 +
===HTTP Response Format===
 +
The server returns a JSON object with the following key-value pairs:
 +
 +
* '''api''': Always "infocenter_json".
 +
* '''status''': Either "ok" or "error".
 +
* '''error''': An error number. Only included if '''status''' is "error". Include this number if possible when contacting support.
 +
* '''text''': A textual status response. If successful, will include how many displays succeeded and failed. If failed, will include a human-readable error message.
 +
 +
===LSL Sample===
 +
A sample LSL script, implementing the JSON sample above, is below:
 +
 +
key api_request;
 +
default
 +
{
 +
    state_entry()
 +
    {
 +
        string json_request = llList2Json(JSON_OBJECT, [
 +
            "request", "\"set_text\"",
 +
            "api_key", "\"1234567890123456\"",
 +
            "frames", llList2Json(JSON_ARRAY, [
 +
                llList2Json(JSON_OBJECT, [
 +
                    "text", "\"Hello World!\"",
 +
                    "color", "",
 +
                    "align", "center",
 +
                    "word_wrap", JSON_TRUE,
 +
                    "ignore_length", JSON_TRUE,
 +
                    "time", 3
 +
                    ]),
 +
                llList2Json(JSON_OBJECT, [
 +
                    "lines", llList2Json(JSON_ARRAY, [
 +
                        llList2Json(JSON_OBJECT, [
 +
                            "text", "\"ABCDEFGHIJKLMNOP\"",
 +
                            "color", "\"ROAYGBPWROAYGBPW\"",
 +
                            "align", "left"
 +
                            ]),
 +
                        llList2Json(JSON_OBJECT, [
 +
                            "text", "\"^^^^^^^^^^^^^^^^\"",
 +
                            "align", "r"
 +
                            ])
 +
                        ]),
 +
                    "ignore_length", JSON_TRUE,
 +
                    "time", 5
 +
                    ]),
 +
                llList2Json(JSON_OBJECT, [
 +
                    "graphic", "\"Stop\"",
 +
                    "time", 3
 +
                    ])
 +
                ])
 +
            ]);
 +
        api_request = llHTTPRequest("http://ntbigroup.com/gentek/infocenter/api_json.php", [HTTP_METHOD, "PUT"], json_request);
 +
    }
 +
    http_response(key request_id, integer status, list metadata, string body)
 +
    {
 +
        if (request_id == api_request)
 +
        {
 +
            api_request = NULL_KEY;
 +
            if (status == 200) llOwnerSay("Response: " + body);
 +
            else llOwnerSay("Server error. (" + (string)status + ")");
 +
        }
 +
    }
 +
}
 +
 +
Note that LSL's JSON handling requires you to wrap values in escaped quotes, like so:
 +
 +
["request", "\"set_text\""]
 +
 +
You do not need to wrap keys in escaped quotes because the specification does not include any keys that could be interpreted as raw JSON.
  
 
{{Gentek}}
 
{{Gentek}}

Revision as of 16:25, 14 March 2020

InfoCenter

InfoCenter Display Kit vendor image.
Creator Nelson Jenkins, SLI Komarov
Launch year 2008, upgraded in 2014
Company Gentek
Availability Marketplace & In-World
InfoCenter Display Kit
InfoCenter Mobile

The InfoCenter is a series of electronic text display signs (Personal, Notice, Highway, Matrix, and Mobile) sold by Gentek. They are designed for transportation & commercial purposes, although have been creatively used for a wide variety of applications. They are all web-controllable and include an API for scripters and web developers.

This page covers the InfoCenter Series v3 and above. Because of the complexity in the new system and licensing restrictions, v3 is not a free update. For older versions, visit these pages: Mobile, Highway, or Personal

Models

The InfoCenter is made up of two separate products - the InfoCenter Display Kit, and the InfoCenter Mobile.

InfoCenter Display Kit

The Display Kit includes the following models (in both standard and Duo variants, Duo typically doubling both the number of lines and characters per line, effectively quadrupling capacity):

  • InfoCenter Personal - 16 x 1 (2 LI) or 32 x 2 (5 LI) characters. Ideal for general commercial use, and includes a variety of animated graphics for stores.
  • InfoCenter Notice - 16 x 7 (8 LI) or 32 x 14 (29 LI) characters. The highest-capacity model, ideal for news & information. Also includes graphics for commercial & industrial purposes.
  • InfoCenter Highway - 16 x 3 (4 LI) or 32 x 6 (13 LI) characters. Best suited for overhead gantry installations on roads, but can be used for walkway or general commercial applications.
  • InfoCenter Matrix - 4 x 2 (1 LI) or 8 x 5 (3 LI) characters. A road sign display with many graphics for lane control, variable speed limits, hazard warning, detours, turn restrictions, and more.

All models, excluding the Highway, have a toggleable mounting bracket. All models are modifiable (scripts excluded) and can be resized or linked (with the caveat that they cannot be linked together).

InfoCenter Mobile

The Mobile model is used for construction & road closures. 8 x 3 characters (3 LI) - the Mobile does not have a Duo variant. It is a trailer unit which can be rotated for the optimum viewing angle. It also has two trailer colors (grey & orange) and the display unit can be resized to three different sizes for different use cases. Unlike other models, the InfoCenter Mobile is not modifiable.

Because of the Mobile's long-lasting popularity over other models, we sell it separately to reduce costs for those just interested in this model. Besides the features above, the Mobile is technically identical to all other models - it is web controllable and uses the same API.

Setup & Use

InfoCenter devices are ready for use out of the box. You can control some cosmetic options described above, but once they are rezzed, they can be set immediately.

All InfoCenter devices are accessible through the InfoCenter Manager. If you access the Manager directly, you will have to log in - you can avoid this by clicking a sign and selecting Web Control. (This will also highlight the selected sign in the manager.)

If you have not created an NTBI Group account before, you will be prompted to enter a password - do not use your SL password for this! Then, in the future, you can log in to the NTBI Group website (including the InfoCenter Manager) without even being in-world.

Setting a Message

You can set any of your InfoCenter devices from the InfoCenter Manager. Click the Set button, and you will be shown the message designer interface.

Messages are made up of slides. Each slide can either be a text slide or a graphic slide, and can be set to display for generally any length of time you want. Slides are displayed sequentially and loop when completed.

The grey number next to the model name for the device you are setting is the maximum number of slides - this is dependent on the capacity of the display, so smaller displays can handle more slides (up to 60). Some very high capacity devices (such as the Notice Duo) can only handle a few slides.

When you open the message designer, the message currently displayed on that device will be shown, so you can edit it if you wish. By default, it is a single blank slide.

  • To add a text slide, type your message into the text cell input area. By default, the Amber color is used, but you can click any color in the palette below to select that color. Any new characters you type will then be in that color. When you're finished, click the Add Text button to add it to the slides.
    • Because of Javascript limitations, you must release each key before typing the next one, otherwise it won't register - type slowly and carefully!
    • Some characters are not permitted as text. If that is the case, they will not be entered.
    • For a full box character, like older InfoCenter models, use the ^ (caret) character. (This will not be shown on the website - it will only appear correctly in-world.)
  • To add a graphic slide, select a graphic from the dropdown. A preview will appear above it. To add the graphic, click Add Graphic.
  • To move slides around or delete them, click the icons next to them. Keep in mind that by default, a blank slide is included as the first slide - you may want to remove it.
  • To change the time that a slide is shown, click Change and type in a new time (in seconds), then click Save. Some high-capacity devices require longer slide times.

When you're finished, click Send To This Device. The message will be sent and displayed immediately in-world. For information on how the Send To Entire Group button works, read Using Groups below.

Using Templates

Templates are a way to easily save and recall messages. Say, for example, that you have 3 different messages you plan on displaying, but only one at a time, and you don't want to retype them every time. Templates allow you to save the message and load it later on that device (or any same-model device).

  • To save a template, design the message that you want to display, then type in a name above the Save As Template button, then click the button. If you already have a template with that name, it will be overwritten, so check first.
  • To load a template, click the dropdown to the right and select the template you want, then click Load. To permanently delete a template, click Delete instead.

Using Groups

Groups are an easy way to control multiple devices at once. Devices can only belong to a single group at a time, but you can have multiple groups. Each group can only support one specific model.

  • To add a device to a group, click the Group button, then enter the name of the group you want to add it to. If the group doesn't exist, it will be created. If it does, the device will simply be added to the group.
  • To remove a device from a group, click the Group button, delete the text in the textbox, and then click OK. This will remove it from the group. If the group no longer has any members, it will be hidden, but not technically deleted - if you recreate that group with the same name, the API key will be retained. (More information on this is in the API section.)
  • To rename a group, click the Rename button next to it, then enter a new group name. This will rename it without changing the API key, and all devices will remain in the group under the new name.
  • To set a message on an entire group, begin by setting a message on a single group member. When you're ready, click Send To Entire Group. This will send the message to all group members.

Renaming & Deleting Devices

When your device is first rezzed, it will be named "Unnamed" followed by a number. Not only is this not descriptive, but it is a bit dangerous - if your display is reset for any reason, it will lose its old name and API key. To rename it, simply click the Rename button and enter a new name. You can also rename it from in-world using the Set Disp ID option.

If your device disappears in-world, it will remain in the InfoCenter Manager. This is intended - it's to prevent accidentally deleting the device if the region is temporarily offline or there is a communication error. You can delete devices from the InfoCenter Manager by clicking Delete. This will not delete it in-world - it will only disappear from the website and lose its API key. If you delete a display while it is still in-world and online, you will get a notification in-world.

Sometimes, you may have several devices which no longer exist, but you don't want to delete them individually. To "flush" non-responsive devices, click the link at the very bottom of the page. This will individually check each device and, if it does not respond, it will be deleted automatically. Note that if a region is offline or very laggy, devices in it may be deleted without warning, so make sure all regions are OK before doing this.

Updates & Release Notes

You can update any InfoCenter product by rezzing it directly from your inventory (each one has an updater script which auto-deletes on first rez, so rezzing a used copy will not work).

  • v3.2
    • Added JSON API (backwards-compatible with earlier versions).
    • Improved font.
    • Fixed bug where graphic frame would be displayed at the same time as rendering text.
  • v3.1
    • Added chat API.
  • v3.0
    • Upgraded public release.
    • Rewrote everything, so old release notes are irrelevant.

API Documentation

For the legacy API, see here.

The InfoCenter signs are controllable using an HTTP/JSON API. This can be used from LSL or from any software or server capable of forming JSON strings and sending HTTP requests.

A sample JSON request is as follows:

{
	"request": "set_text",
	"api_key": "1234567890123456",
	"frames": [
		{
			"text": "Hello World!",
			"color": "",
			"align": "center",
			"word_wrap": true,
			"ignore_length": true,
			"time": 3
		},
		{
			"lines": [
				{
					"text": "ABCDEFGHIJKLMNOP",
					"color": "ROAYGBPWROAYGBPW",
					"align": "left"
				},
				{
					"text": "^^^^^^^^^^^^^^^^",
					"align": "right"
				}
			],
			"ignore_length": true,
			"time": 3
		},
		{
			"graphic": "Stop",
			"time": 3
		}
	]
}

Required Key/Values

The JSON request must be an object with the following key-value pairs:

  • request: Must be "set_text".
  • api_key: The API key of the display or group to set.
  • frames: An array of objects, each object being a single frame.

Frame Object

Each frame must have only one of these required key-value pairs:

  • text: A string of text to display.
  • lines: An array of objects, each object being a single line on the display. Allows more precision in where text is displayed.
  • graphic: The name of a graphic supported by this display (see below).

The key-value above used determines which type of frame it is, which determines which options are available.

Text Frame Type

A text frame type can have the following options:

  • text: Required. A string of text to display.
  • color: Optional. A color string (see below). If an empty string or not defined, "A" is used.
    • If the color string is shorter than the text string, the rest of the text uses the last color character.
    • If word_wrap is enabled, the entire frame will only be the color of the last color character due to technical limitations.
  • align: Optional. Either "left", "center", or "right". Can also be "l", "c", or "r". If not defined, aligned to left.
    • If word_wrap is enabled, this will align each line. If it is disabled, this will only align the last line, because the lines before it (if any) will be the full width of the display.
  • word_wrap: Optional. Must be true to enable (JSON_TRUE in LSL). If enabled, words are wrapped naturally. If disabled or not defined, text is "hard" wrapped to the full width of the display. It is a good idea to enable ignore_length to avoid errors if words wrap beyond the limits of the display.
  • ignore_length: Optional. Must be true to enable (JSON_TRUE in LSL). If enabled, the server will not check the length of the text. If disabled or not defined, the server will return an error if the text exceeds the maximum the display can show.
  • time: Optional. A length of time in seconds, between 1 and 3600, to display the frame. If not defined, the time will default to 5 seconds.
    • The server does not check the minimum time it would take to render the display, so very short frame times may produce unintended results.

Lines Frame Type

A lines frame type can have the following options:

  • lines: Required. An array of objects, each object being a single line on the display. Allows more precision in where text is displayed. Each line can have the following options:
    • text: Required. A string of text to display on the line.
    • color: Optional. Optional. A color string (see below). If the color string is shorter than the text string, the rest of the text uses the last color character. If the color option is not defined or is empty, "A" is used. If an invalid character is used, it is replaced with "W".
    • align: Optional. Either "left", "center", or "right". Can also be "l", "c", or "r". If not defined, aligned to left.
  • ignore_length: Optional. Must be true to enable (JSON_TRUE in LSL). If enabled, the server will not check the length of the text on each line, nor will it check the number of lines included in the request. If disabled or not defined, the server will return an error if the text exceeds the maximum the display can show in either dimension.
  • time: Optional. A length of time in seconds, between 1 and 3600, to display the frame. If not defined, the time will default to 5 seconds.
    • The server does not check the minimum time it would take to render the display, so very short frame times may produce unintended results.

Graphic Frame Type

A graphic frame type can have the following options:

  • graphic: The name of a graphic supported by this display. This is case-insensitive, but must otherwise be an exact match to a supported graphic, or the server will return an error. The supported graphics are as follows:
    • InfoCenter Highway: "Stop", "Hazard", "Do Not Enter"
    • InfoCenter Matrix: "Stop", "Hazard", "Do Not Enter", "Detour Left", "Detour Right", "Lane Open Down", "Lane Open Up", "Lane Closed", "Lane Left Down", "Lane Right Down", "Lane Left Up", "Lane Right Up", "One Way Left", "One Way Right", "Yield", "Do Not Pass", "Stay In Lane", "No Trucks", "Trucks OK", "Speed Limit 5", "Speed Limit 10", "Speed Limit 15", "Speed Limit 20", "Speed Limit 25", "Speed Limit 30", "Speed Limit 35", "Speed Limit 40", "Speed Limit 45", "Speed Limit 50", "Speed Limit 55", "Speed Limit 60", "Speed Limit 65", "Speed Limit 70", "Speed Limit 75", "Speed Limit 80", "Keep Right", "Keep Left", "No Right Turn", "No Left/U Turn", "No Left Turn", "No U Turn", "Straight Or Left", "Straight Or Right", "Straight Only", "Left Turn Only", "Right Turn Only", "No Turns"
    • InfoCenter Notice: "Information", "Today's Events", "Huge Sale", "Discounts", "Best Deals", "Notice", "Warning", "Danger"
    • InfoCenter Personal: "Sale", "Come On In", "News Flash", "Happy 4th", "Welcome", "Open", "Closed", "Thank You", "No Smoking"
    • InfoCenter Mobile: "Stop", "Hazard", "Do Not Enter", "Chase Right", "Chase Left", "Arrow Right", "Arrow Left", "Flash Right", "Flash Left", "Chevron Right", "Chevron Left", "Arrow Split", "Flash Split", "Flagger", "Stop Left", "Stop Right", "Detour Left", "Detour Right"
  • time: Optional. A length of time in seconds, between 1 and 3600, to display the frame. If not defined, the time will default to 5 seconds.

HTTP Request Format

The required URL, as part of an LSL HTTP request, is as follows:

llHTTPRequest("http://ntbigroup.com/gentek/infocenter/api_json.php", [HTTP_METHOD, "PUT"], json_request);

This URL is also accessible from any web server.

HTTP Response Format

The server returns a JSON object with the following key-value pairs:

  • api: Always "infocenter_json".
  • status: Either "ok" or "error".
  • error: An error number. Only included if status is "error". Include this number if possible when contacting support.
  • text: A textual status response. If successful, will include how many displays succeeded and failed. If failed, will include a human-readable error message.

LSL Sample

A sample LSL script, implementing the JSON sample above, is below:

key api_request;
default
{
    state_entry()
    {
        string json_request = llList2Json(JSON_OBJECT, [
            "request", "\"set_text\"",
            "api_key", "\"1234567890123456\"",
            "frames", llList2Json(JSON_ARRAY, [
                llList2Json(JSON_OBJECT, [
                    "text", "\"Hello World!\"",
                    "color", "",
                    "align", "center",
                    "word_wrap", JSON_TRUE,
                    "ignore_length", JSON_TRUE,
                    "time", 3
                    ]),
                llList2Json(JSON_OBJECT, [
                    "lines", llList2Json(JSON_ARRAY, [
                        llList2Json(JSON_OBJECT, [
                            "text", "\"ABCDEFGHIJKLMNOP\"",
                            "color", "\"ROAYGBPWROAYGBPW\"",
                            "align", "left"
                            ]),
                        llList2Json(JSON_OBJECT, [
                            "text", "\"^^^^^^^^^^^^^^^^\"",
                            "align", "r"
                            ])
                        ]),
                    "ignore_length", JSON_TRUE,
                    "time", 5
                    ]),
                llList2Json(JSON_OBJECT, [
                    "graphic", "\"Stop\"",
                    "time", 3
                    ])
                ])
            ]);
        api_request = llHTTPRequest("http://ntbigroup.com/gentek/infocenter/api_json.php", [HTTP_METHOD, "PUT"], json_request);
    }
    http_response(key request_id, integer status, list metadata, string body)
    {
        if (request_id == api_request)
        {
            api_request = NULL_KEY;
            if (status == 200) llOwnerSay("Response: " + body);
            else llOwnerSay("Server error. (" + (string)status + ")");
        }
    }
}

Note that LSL's JSON handling requires you to wrap values in escaped quotes, like so:

["request", "\"set_text\""]

You do not need to wrap keys in escaped quotes because the specification does not include any keys that could be interpreted as raw JSON.