Added support for Linear AE-100 and AE-500

This commit is contained in:
Erik C. Thauvin 2016-08-30 00:27:13 -07:00
parent 77d5e3d835
commit ae77e94cd6
15 changed files with 780 additions and 135 deletions

View file

@ -8,7 +8,11 @@ Program your Telephone Entry System remotely (off-site) using your phone.
Most Telephone Entry Systems can be programmed from the front keypad or remotely from an off-premise location using any touch-tone phone. TES Remote Programmer streamlines the often cumbersome remote programming process by providing data entry screens and automated dial-in options.
By default, TES Remote Programmer is configured to work with the [DoorKing (DKS) 1802, 1802-EPD, 1803, 1808, 1810 and 1819](http://www.doorking.com/telephone/) systems, additional [configurations](#configurations) can be created for most systems supporting remote programming.
### DoorKing (DKS) & Linear
By default, TES Remote Programmer is configured to work with the [DoorKing (DKS) 1802, 1802-EPD, 1803, 1808, 1810 and 1819](http://www.doorking.com/telephone/) as well as the [Linear AE-100 and AE-500](http://www.linearproaccess.com/access-controls/telephone-entry-systems/) systems, additional [configurations](#configurations) can be created for most systems supporting remote programming.
### Directory Code
Please note that all default configurations are set for 3-digits directory code length. If your system is setup differently, you will need to modify the [default configuration](app/src/main/res/raw/) and re-import it. Look for all `Directory Code` fields and modify their `size` attributes accordingly.
@ -43,8 +47,8 @@ Parameters define the configuration's global settings.
```json
"params": {
"name": "DKS 1802-EPD",
"star": "*",
"hash": "#",
"ack": "*",
"alt": "#",
"end": "0 + #",
"size": 4
}
@ -53,8 +57,9 @@ Parameters define the configuration's global settings.
| Parameter | Description | Required |
|:-----------|:-------------------------------------------------------------------------------------------------|:---------|
|`name` | The name of the configuration. | Yes |
|`star` | The key used to start, acknowledge or terminate programming steps. Most systems use the `*` key. | Yes |
|`hash` | They key used to in place of numbers when applicable. Most system use the `#` key | No |
|`ack` | The key used to acknowledge or terminate programming steps. Most systems use the `*` or `#` key. | Yes |
|`alt` | They key used to in place of numbers when applicable. DKS systems use the `#` key | No |
|`begin` | The begin programming manual sequence. For example Linear use `0` and `2` pressed together. | No |
|`end` | The end programming manual sequence. For example DoorKing uses `0` and `#` pressed together. | No |
|`size` | The size (number of digits) of the master code. Most systems use 4 or 5. | Yes |
@ -83,7 +88,7 @@ which would translate into:
{
"hint": "Phone Number",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*01[MASTER],[FIELD:1]*,[FIELD:2]*"
@ -93,7 +98,7 @@ which would translate into:
Step 4 is configured in the `end` [parameter](#parameters) since it only applies to manual/keypad programming.
| Elements | Description |
| Property | Description |
|:---------|:--------------------------------------------------------------------------------------------------|
|`title` | The title of the option. |
|`fields` | See [Fields](#fields) |
@ -114,21 +119,23 @@ All are required, except `nodial` and `nosteps` which are mutually exclusive.
{
"hint": "Phone Number",
"size": 7,
"hash": true
"alt": true
}
]
```
Fields represent the data entry text fields on option screens.
| Element | Description | Required |
|:--------|:--------------------------------------------------------------------------------------------------|:---------|
|`hint` | Set the hint/label of the field. | Yes |
|`size` | Set the size of the field. | Yes |
|`min` | Set the minimum value of a numeric field. | No |
|`max` | Set the maximum value of a numeric field. | No |
|`alpha` | Set to `true` if the field is alphanumeric. | No |
|`hash` | Set to `true` if the field accept the `hash` [parameter](#parameters) value in place of a digit. | No |
| Property | Description | Required |
|:---------|:------------------------------------------------------------------------------------------------------|:---------|
|`hint` | Set the hint/label of the field. | Yes |
|`size` | Set the size of the field. | Yes |
|`minSize` | Set the minimum size of the field. If set, `size` is the maximum size of the field. | No |
|`min` | Set the minimum value of a numeric field. | No |
|`max` | Set the maximum value of a numeric field. | No |
|`alpha` | Set to `dks` or `linear` for alphanumeric fields. | No |
|`alt` | Set to `true` if the field accepts the `alt` [parameter](#parameters) value in place of a digit. | No |
|`zeros` | Set to `true` by default. Allows numeric values with leading zeros (i.e. `001`), based on the `size`. | No |
#### DTMF
@ -153,5 +160,3 @@ Imported configurations will be validated. While the validation is not perfect,
Please sure to use a JSON editor to make creating configurations a whole lot easier.
When in doubt be sure to look at the [default configurations](app/src/main/res/raw/).

View file

@ -64,6 +64,8 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
R.raw.dks_1802_epd,
R.raw.dks_1812,
R.raw.dks_1819,
R.raw.linear_ae_100,
R.raw.linear_ae_500,
R.raw.dks_1803_1808_1810)
val read_request_code = 42
@ -348,8 +350,8 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
errors.append(getString(R.string.validate_invalid_param, "size"))
}
if (params.star.isBlank()) {
errors.append(getString(R.string.validate_missing_param, "star"))
if (params.ack.isBlank()) {
errors.append(getString(R.string.validate_missing_param, "ack"))
}
if (opts.size == 0) {
@ -374,7 +376,13 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "size"))
}
if (!field.alpha) {
if (field.minSize == 0) {
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "minSize"))
} else if (field.minSize > 0 && field.minSize > field.size) {
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "minSize/size"))
}
if (field.alpha.isBlank()) {
if (field.min >= 0 || field.max >= 0) {
if (field.max < 1) {
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "max"))
@ -393,7 +401,7 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
val blank = "\\0"
val dtmf = Dtmf.mock(option, blank)
if (!Dtmf.validate(dtmf, "${MainActivity.Companion.PAUSE}${params.star}${params.hash}$blank")) {
if (!Dtmf.validate(dtmf, "${MainActivity.Companion.PAUSE}${params.ack}${params.alt}$blank")) {
errors.append(getString(R.string.validate_invalid_dtmf, i + 1, dtmf.replace(blank, "&#10003;")))
}
}

View file

@ -98,15 +98,21 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger {
val editText = editText() {
hint = field.hint
if (field.alpha) {
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
inputFilters.add(AlphaFilter())
if (field.alpha.isNotBlank()) {
if (field.alpha.equals(Dtmf.DKS, true)) {
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
inputFilters.add(AlphaFilter(Dtmf.DKS_EXTRAS))
} else if (field.alpha.equals(Dtmf.LINEAR, true)) {
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
inputFilters.add(AlphaFilter(Dtmf.LINEAR_EXTRAS))
}
} else {
inputType = InputType.TYPE_CLASS_PHONE
inputFilters.add(NumberFilter("0123456789" +
if (field.hash) "${params.hash}" else ""))
if (field.alt) "${params.alt}" else ""))
if (field.max != -1 && field.min != -1) {
inputFilters.add(MinMaxFilter(field.min, field.max, field.size))
inputFilters.add(
MinMaxFilter(field.min, field.max, field.size, field.zeros))
}
}
@ -148,10 +154,22 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger {
onClick {
if (validateFields(fields, option)) {
val dtmf = Dtmf.build(params.master, params.star, option, fields)
if (Dtmf.validate(dtmf, "${MainActivity.PAUSE}${params.star}${params.hash}")) {
val dtmf = Dtmf.build(params.master, params.ack, option, fields)
if (Dtmf.validate(dtmf, "${MainActivity.PAUSE}${params.ack}${params.alt}")) {
val begin = if (params.begin.isNotBlank()) {
"${params.begin}${MainActivity.PAUSE}"
} else {
""
}
val end = if (params.end.isNotBlank()) {
"${MainActivity.PAUSE}${params.end}"
} else {
""
}
startActivity<StepsActivity>(
StepsActivity.EXTRA_STEPS to "$dtmf${MainActivity.PAUSE}${params.end}".split(','))
StepsActivity.EXTRA_STEPS to "$begin$dtmf$end".split(','))
} else {
Snackbar.make(this@coordinatorLayout, getString(R.string.error_invalid_dtmf, dtmf),
Snackbar.LENGTH_LONG).show()
@ -181,8 +199,8 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger {
imageResource = R.drawable.fab_ic_call
onClick {
if (validateFields(fields, option)) {
val dtmf = Dtmf.build(params.master, params.star, option, fields)
if (Dtmf.validate(dtmf, "${MainActivity.PAUSE}${params.star}${params.hash}")) {
val dtmf = Dtmf.build(params.master, params.ack, option, fields)
if (Dtmf.validate(dtmf, "${MainActivity.PAUSE}${params.ack}${params.alt}")) {
ProgrammingActivityPermissionsDispatcher.callWithCheck(
this@ProgrammingActivity, params.phone, dtmf)
} else {
@ -214,7 +232,9 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger {
@NeedsPermission(Manifest.permission.CALL_PHONE)
fun call(phone: String, dtmf: String) {
info("$phone${MainActivity.PAUSE}${MainActivity.PAUSE}$dtmf")
if (BuildConfig.DEBUG) {
info(">>> $phone${MainActivity.PAUSE}${MainActivity.PAUSE}$dtmf")
}
makeCall("$phone${MainActivity.PAUSE}${MainActivity.PAUSE}$dtmf")
}
@ -226,15 +246,40 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger {
v.error = getString(R.string.error_required)
isValid = false
} else {
val size = option.fields[i].size
if (!option.fields[i].alpha && size > 0 && (v.length() != size)) {
val size = if (option.fields[i].minSize > 0) {
option.fields[i].minSize
} else {
option.fields[i].size
}
if (option.fields[i].alpha.isBlank() &&
!validateSize(v.length(), option.fields[i].minSize, option.fields[i].size)) {
v.error = getString(R.string.error_invalid_size, size,
resources.getQuantityString(R.plurals.error_digit, size))
isValid = false
}
if (option.fields[i].min > 0 && option.fields[i].max > 0) {
try {
if (v.text.toString().toInt() !in IntRange(option.fields[i].min, option.fields[i].max)) {
v.error = getString(R.string.error_invalid)
isValid = false
}
} catch (nfe: NumberFormatException) {
v.error = getString(R.string.error_invalid)
isValid = false
}
}
}
}
return isValid
}
fun validateSize(size: Int, min: Int, max: Int): Boolean {
if (min > 0) {
return size in IntRange(min, max)
} else {
return size == max
}
}
}

View file

@ -22,6 +22,12 @@ import android.text.SpannableStringBuilder
import android.text.Spanned
class AlphaFilter : InputFilter {
private val extras: String
constructor(extras: String) {
this.extras = extras
}
override fun filter(source: CharSequence,
start: Int,
end: Int,
@ -32,7 +38,7 @@ class AlphaFilter : InputFilter {
if (source is SpannableStringBuilder) {
for (i in end - 1 downTo start) {
val c = source[i]
if (!c.isLetterOrDigit() && !Character.isSpaceChar(c)) {
if (!c.isLetterOrDigit() && !extras.contains(c)) {
source.delete(i, i + 1)
}
}
@ -41,7 +47,7 @@ class AlphaFilter : InputFilter {
val sb = StringBuilder()
for (i in start..end - 1) {
val c = source[i]
if (c.isLetterOrDigit() || Character.isSpaceChar(c)) {
if (c.isLetterOrDigit() || extras.contains(c)) {
sb.append(c.toUpperCase())
}
}

View file

@ -22,8 +22,10 @@ import android.os.Parcelable
import java.io.Serializable
data class Field(var hint: String,
var alpha: Boolean,
val hash: Boolean,
var alpha: String,
val alt: Boolean,
var zeros: Boolean,
var minSize: Int,
var size: Int,
var min: Int,
var max: Int) : Parcelable, Serializable {
@ -37,22 +39,26 @@ data class Field(var hint: String,
}
}
constructor() : this("", false, false, -1, -1, -1)
constructor() : this("", "", false, true, -1, -1, -1, -1)
constructor(source: Parcel) : this(
source.readString(),
source.readString(),
1.equals(source.readInt()),
1.equals(source.readInt()),
source.readInt(),
source.readInt(),
source.readInt(),
source.readInt())
override fun describeContents() = 0
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest?.writeString(hint)
dest?.writeInt((if (alpha) 1 else 0))
dest?.writeInt((if (hash) 1 else 0))
dest?.writeString(alpha)
dest?.writeInt((if (alt) 1 else 0))
dest?.writeInt((if (zeros) 1 else 0))
dest?.writeInt(minSize)
dest?.writeInt(size)
dest?.writeInt(min)
dest?.writeInt(max)

View file

@ -25,8 +25,9 @@ data class Params(var name: String,
var phone: String,
var master: String,
var size: Int,
var star: String,
var hash: String,
var ack: String,
var alt: String,
var begin: String,
var end: String) : Parcelable, Serializable {
companion object {
@ -38,7 +39,7 @@ data class Params(var name: String,
}
}
constructor() : this("", "", "", -1, "", "", "")
constructor() : this("", "", "", -1, "", "", "", "")
constructor(source: Parcel) : this(
source.readString(),
@ -47,7 +48,8 @@ data class Params(var name: String,
source.readInt(),
source.readString(),
source.readString(),
source.readString())
source.readString(),
source.readString())
override fun describeContents() = 0
@ -56,8 +58,9 @@ data class Params(var name: String,
dest?.writeString(phone)
dest?.writeString(master)
dest?.writeInt(size)
dest?.writeString(star)
dest?.writeString(hash)
dest?.writeString(ack)
dest?.writeString(alt)
dest?.writeString(begin)
dest?.writeString(end)
}
}

View file

@ -26,74 +26,141 @@ class Dtmf {
companion object {
val DTMF_MASTER = "[MASTER]"
val DTMF_FIELD = "[FIELD:%1\$d]"
val DKS = "dks"
val LINEAR = "linear"
val DKS_EXTRAS = " "
val LINEAR_EXTRAS = ", -."
private fun alphaToDigits(text: String, star: String): String {
private fun linearAlphaToDigits(text: String): String {
val result = StringBuffer()
text.toUpperCase().forEach { c ->
when (c) {
'A' -> result.append("2$star${MainActivity.PAUSE}")
'B' -> result.append("22$star${MainActivity.PAUSE}")
'C' -> result.append("2222$star${MainActivity.PAUSE}")
'A' -> result.append("1${MainActivity.PAUSE}")
'B' -> result.append("11${MainActivity.PAUSE}")
'C' -> result.append("111${MainActivity.PAUSE}")
'D' -> result.append("3$star${MainActivity.PAUSE}")
'E' -> result.append("33$star${MainActivity.PAUSE}")
'F' -> result.append("333$star${MainActivity.PAUSE}")
'D' -> result.append("2${MainActivity.PAUSE}")
'E' -> result.append("22${MainActivity.PAUSE}")
'F' -> result.append("222${MainActivity.PAUSE}")
'G' -> result.append("4$star${MainActivity.PAUSE}")
'H' -> result.append("44$star${MainActivity.PAUSE}")
'I' -> result.append("444$star${MainActivity.PAUSE}")
'G' -> result.append("3${MainActivity.PAUSE}")
'H' -> result.append("33${MainActivity.PAUSE}")
'I' -> result.append("333${MainActivity.PAUSE}")
'J' -> result.append("5$star${MainActivity.PAUSE}")
'K' -> result.append("55$star${MainActivity.PAUSE}")
'L' -> result.append("555$star${MainActivity.PAUSE}")
'J' -> result.append("4${MainActivity.PAUSE}")
'K' -> result.append("44${MainActivity.PAUSE}")
'L' -> result.append("444${MainActivity.PAUSE}")
'M' -> result.append("6$star${MainActivity.PAUSE}")
'N' -> result.append("66$star${MainActivity.PAUSE}")
'O' -> result.append("666$star${MainActivity.PAUSE}")
'M' -> result.append("5${MainActivity.PAUSE}")
'N' -> result.append("55${MainActivity.PAUSE}")
'O' -> result.append("555${MainActivity.PAUSE}")
'P' -> result.append("7$star${MainActivity.PAUSE}")
'Q' -> result.append("77$star${MainActivity.PAUSE}")
'R' -> result.append("777$star${MainActivity.PAUSE}")
'S' -> result.append("7777$star${MainActivity.PAUSE}")
'P' -> result.append("6${MainActivity.PAUSE}")
'Q' -> result.append("66${MainActivity.PAUSE}")
'R' -> result.append("666${MainActivity.PAUSE}")
'T' -> result.append("8$star${MainActivity.PAUSE}")
'U' -> result.append("88$star${MainActivity.PAUSE}")
'V' -> result.append("888$star${MainActivity.PAUSE}")
'S' -> result.append("7${MainActivity.PAUSE}")
'T' -> result.append("77${MainActivity.PAUSE}")
'U' -> result.append("777${MainActivity.PAUSE}")
'W' -> result.append("9$star${MainActivity.PAUSE}")
'X' -> result.append("99$star${MainActivity.PAUSE}")
'Y' -> result.append("999$star${MainActivity.PAUSE}")
'Z' -> result.append("9999$star${MainActivity.PAUSE}")
'V' -> result.append("8${MainActivity.PAUSE}")
'W' -> result.append("88${MainActivity.PAUSE}")
'X' -> result.append("888${MainActivity.PAUSE}")
'0' -> result.append("0$star${MainActivity.PAUSE}")
'1' -> result.append("11$star${MainActivity.PAUSE}")
'2' -> result.append("2222$star${MainActivity.PAUSE}")
'3' -> result.append("3333$star${MainActivity.PAUSE}")
'4' -> result.append("4444$star${MainActivity.PAUSE}")
'5' -> result.append("5555$star${MainActivity.PAUSE}")
'6' -> result.append("6666$star${MainActivity.PAUSE}")
'7' -> result.append("77777$star${MainActivity.PAUSE}")
'8' -> result.append("8888$star${MainActivity.PAUSE}")
'9' -> result.append("99999$star${MainActivity.PAUSE}")
'Y' -> result.append("9${MainActivity.PAUSE}")
'Z' -> result.append("99${MainActivity.PAUSE}")
',' -> result.append("999${MainActivity.PAUSE}")
' ' -> result.append("1$star${MainActivity.PAUSE}")
'0' -> result.append("0000${MainActivity.PAUSE}")
'1' -> result.append("1111${MainActivity.PAUSE}")
'2' -> result.append("2222${MainActivity.PAUSE}")
'3' -> result.append("3333${MainActivity.PAUSE}")
'4' -> result.append("4444${MainActivity.PAUSE}")
'5' -> result.append("5555${MainActivity.PAUSE}")
'6' -> result.append("6666${MainActivity.PAUSE}")
'7' -> result.append("7777${MainActivity.PAUSE}")
'8' -> result.append("8888${MainActivity.PAUSE}")
'9' -> result.append("9999${MainActivity.PAUSE}")
' ' -> result.append("0${MainActivity.PAUSE}")
'-' -> result.append("00${MainActivity.PAUSE}")
'.' -> result.append("0000${MainActivity.PAUSE}")
}
}
return result.toString()
}
private fun dksAlphaToDigits(text: String, ack: String): String {
val result = StringBuffer()
text.toUpperCase().forEach { c ->
when (c) {
'A' -> result.append("2$ack${MainActivity.PAUSE}")
'B' -> result.append("22$ack${MainActivity.PAUSE}")
'C' -> result.append("222$ack${MainActivity.PAUSE}")
'D' -> result.append("3$ack${MainActivity.PAUSE}")
'E' -> result.append("33$ack${MainActivity.PAUSE}")
'F' -> result.append("333$ack${MainActivity.PAUSE}")
'G' -> result.append("4$ack${MainActivity.PAUSE}")
'H' -> result.append("44$ack${MainActivity.PAUSE}")
'I' -> result.append("444$ack${MainActivity.PAUSE}")
'J' -> result.append("5$ack${MainActivity.PAUSE}")
'K' -> result.append("55$ack${MainActivity.PAUSE}")
'L' -> result.append("555$ack${MainActivity.PAUSE}")
'M' -> result.append("6$ack${MainActivity.PAUSE}")
'N' -> result.append("66$ack${MainActivity.PAUSE}")
'O' -> result.append("666$ack${MainActivity.PAUSE}")
'P' -> result.append("7$ack${MainActivity.PAUSE}")
'Q' -> result.append("77$ack${MainActivity.PAUSE}")
'R' -> result.append("777$ack${MainActivity.PAUSE}")
'S' -> result.append("7777$ack${MainActivity.PAUSE}")
'T' -> result.append("8$ack${MainActivity.PAUSE}")
'U' -> result.append("88$ack${MainActivity.PAUSE}")
'V' -> result.append("888$ack${MainActivity.PAUSE}")
'W' -> result.append("9$ack${MainActivity.PAUSE}")
'X' -> result.append("99$ack${MainActivity.PAUSE}")
'Y' -> result.append("999$ack${MainActivity.PAUSE}")
'Z' -> result.append("9999$ack${MainActivity.PAUSE}")
'0' -> result.append("0$ack${MainActivity.PAUSE}")
'1' -> result.append("11$ack${MainActivity.PAUSE}")
'2' -> result.append("2222$ack${MainActivity.PAUSE}")
'3' -> result.append("3333$ack${MainActivity.PAUSE}")
'4' -> result.append("4444$ack${MainActivity.PAUSE}")
'5' -> result.append("5555$ack${MainActivity.PAUSE}")
'6' -> result.append("6666$ack${MainActivity.PAUSE}")
'7' -> result.append("77777$ack${MainActivity.PAUSE}")
'8' -> result.append("8888$ack${MainActivity.PAUSE}")
'9' -> result.append("99999$ack${MainActivity.PAUSE}")
' ' -> result.append("1$ack${MainActivity.PAUSE}")
}
}
return result.toString()
}
fun build(master: String,
star: String,
ack: String,
option: Option,
fields: ArrayList<EditText>): String {
val replace = arrayListOf(Pair("$DTMF_MASTER", master))
fields.forEachIndexed { i, field ->
replace.add(Pair(DTMF_FIELD.format(i + 1),
if (option.fields[i].alpha) {
alphaToDigits(field.text.toString(), star)
} else {
if (option.fields[i].alpha.equals(DKS, true)) {
dksAlphaToDigits(field.text.toString(), ack)
} else if (option.fields[i].alpha.equals(LINEAR, true)) {
linearAlphaToDigits(field.text.toString())
}
else {
field.text.toString()
}))
}

View file

@ -1,8 +1,8 @@
{
"params": {
"name": "DKS 1802",
"star": "*",
"hash": "#",
"ack": "*",
"alt": "#",
"end": "0 + #",
"size": 4
},
@ -17,7 +17,7 @@
{
"hint": "Phone Number",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*01[MASTER],[FIELD:1]*,[FIELD:2]*"
@ -32,7 +32,7 @@
{
"hint": "Phone Number",
"size": 16,
"hash": true
"alt": true
}
],
"dtmf": "*01[MASTER],[FIELD:1]*,[FIELD:2]*"
@ -225,7 +225,7 @@
"size": 4,
"min": 1,
"max": 15,
"hash": true
"alt": true
}
],
"dtmf": "*24[MASTER],[FIELD:1]*,[FIELD:2]*"
@ -330,7 +330,7 @@
{
"hint": "Days of Week (Sun=1, Sat=7 or #)",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*35[MASTER],[FIELD:1]*,[FIELD:2]*,[FIELD:3][FIELD:4]*,[FIELD:5]*,[FIELD:6][FIELD:7]*,[FIELD:8]*,[FIELD:9]*"
@ -383,7 +383,7 @@
{
"hint": "Days of Week (Sun=1..Sat=7 or #)",
"size": 7,
"hash": true
"alt": true
},
{
"hint": "Lower 4-Digit Boundary",
@ -456,7 +456,7 @@
{
"hint": "Days of Week (Sun=1..Sat=7 or #)",
"size": 7,
"hash": true
"alt": true
},
{
"hint": "Lower 4-Digit Boundary",
@ -497,7 +497,7 @@
{
"hint": "Phone Number",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*41[MASTER],[FIELD:1]*,[FIELD:2]*,[FIELD:3]*"

View file

@ -1,8 +1,8 @@
{
"params": {
"name": "DKS 1802-EPD",
"star": "*",
"hash": "#",
"ack": "*",
"alt": "#",
"end": "0 + #",
"size": 4
},
@ -17,7 +17,7 @@
{
"hint": "Phone Number",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*01[MASTER],[FIELD:1]*,[FIELD:2]*"
@ -32,7 +32,7 @@
{
"hint": "Phone Number",
"size": 16,
"hash": true
"alt": true
}
],
"dtmf": "*01[MASTER],[FIELD:1]*,[FIELD:2]*"
@ -225,7 +225,7 @@
"size": 4,
"min": 1,
"max": 15,
"hash": true
"alt": true
}
],
"dtmf": "*24[MASTER],[FIELD:1]*,[FIELD:2]*"
@ -330,7 +330,7 @@
{
"hint": "Days of Week (Sun=1, Sat=7 or #)",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*35[MASTER],[FIELD:1]*,[FIELD:2]*,[FIELD:3][FIELD:4]*,[FIELD:5]*,[FIELD:6][FIELD:7]*,[FIELD:8]*,[FIELD:9]*"
@ -383,7 +383,7 @@
{
"hint": "Days of Week (Sun=1..Sat=7 or #)",
"size": 7,
"hash": true
"alt": true
},
{
"hint": "Lower 4-Digit Boundary",
@ -456,7 +456,7 @@
{
"hint": "Days of Week (Sun=1..Sat=7 or #)",
"size": 7,
"hash": true
"alt": true
},
{
"hint": "Lower 4-Digit Boundary",
@ -497,7 +497,7 @@
{
"hint": "Phone Number",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*41[MASTER],[FIELD:1]*,[FIELD:2]*,[FIELD:3]*"
@ -512,7 +512,7 @@
{
"hint": "Name",
"size": 11,
"alpha": true
"alpha": "dks"
}
],
"nodial": true,
@ -524,17 +524,17 @@
{
"hint": "Message (Line 1)",
"size": 16,
"alpha": true
"alpha": "dks"
},
{
"hint": "Message (Line 2)",
"size": 16,
"alpha": true
"alpha": "dks"
},
{
"hint": "Message (Line 3)",
"size": 16,
"alpha": true
"alpha": "dks"
}
],
"nodial": true,
@ -546,17 +546,17 @@
{
"hint": "Message (Line 1)",
"size": 16,
"alpha": true
"alpha": "dks"
},
{
"hint": "Message (Line 2)",
"size": 16,
"alpha": true
"alpha": "dks"
},
{
"hint": "Message (Line 3)",
"size": 16,
"alpha": true
"alpha": "dks"
}
],
"nodial": true,

View file

@ -1,8 +1,8 @@
{
"params": {
"name": "DKS 1803/1808/1810",
"star": "*",
"hash": "#",
"ack": "*",
"alt": "#",
"end": "0 + #",
"size": 4
},
@ -17,7 +17,7 @@
{
"hint": "Phone Number",
"size": 16,
"hash": true
"alt": true
}
],
"dtmf": "*01[MASTER],[FIELD:1]*,[FIELD:2]*"
@ -202,7 +202,7 @@
{
"hint": "Days of Week (Sun=1, Sat=7 or #)",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*35[MASTER],[FIELD:1][FIELD:2]*,[FIELD:3][FIELD:4]*,[FIELD:5]*,[FIELD:6]*,[FIELD:7]*"
@ -231,7 +231,7 @@
{
"hint": "Days of Week (Sun=1..Sat=7 or #)",
"size": 7,
"hash": true
"alt": true
},
{
"hint": "Lower 4-Digit Boundary",
@ -268,7 +268,7 @@
{
"hint": "Days of Week (Sun=1, Sat=7 or #)",
"size": 7,
"hash": true
"alt": true
},
{
"hint": "Lower 5-Digit Boundary",

View file

@ -1,8 +1,8 @@
{
"params": {
"name": "DKS 1812",
"star": "*",
"hash": "#",
"ack": "*",
"alt": "#",
"end": "0 + #",
"size": 4
},
@ -113,7 +113,7 @@
{
"hint": "Active Days of Week (Sun=1..Sat=7, or #)",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*34[MASTER],[FIELD:1]*,[FIELD:2][FIELD:3]*,[FIELD:4]*,[FIELD:5]*"
@ -148,7 +148,7 @@
{
"hint": "Active Days of Week (Sun=1..Sat=7, or #)",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*35[MASTER],[FIELD:1]*,[FIELD:2][FIELD:3]*,[FIELD:4]*,[FIELD:5]*"
@ -201,7 +201,7 @@
{
"hint": "Active Days of Week (Sun=1..Sat=7, or #)",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*36[MASTER],[FIELD:1]*,[FIELD:2][FIELD:3][FIELD:4]*,[FIELD:5][FIELD:6][FIELD:7]*,[FIELD:8]"
@ -254,7 +254,7 @@
{
"hint": "Active Days of Week (Sun=1..Sat=7, or #)",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*37[MASTER],[FIELD:1]*,[FIELD:2][FIELD:3][FIELD:4]*,[FIELD:5][FIELD:6][FIELD:7]*,[FIELD:8]"
@ -283,7 +283,7 @@
{
"hint": "Area Code (1..., #... or ####)",
"size": 4,
"hash": true
"alt": true
},
{
"hint": "Phone Number",
@ -316,7 +316,7 @@
{
"hint": "Area Code (1..., #... or ####)",
"size": 4,
"hash": true
"alt": true
},
{
"hint": "Phone Number",

View file

@ -1,8 +1,8 @@
{
"params": {
"name": "DKS 1819",
"star": "*",
"hash": "#",
"ack": "*",
"alt": "#",
"end": "0 + #",
"size": 4
},
@ -25,7 +25,7 @@
{
"hint": "Phone Number",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*01[MASTER],001*,[FIELD:1]*"
@ -44,7 +44,7 @@
"size": 4,
"min": 1,
"max": 15,
"hash": true
"alt": true
}
],
"dtmf": "*24[MASTER],[FIELD:1]*,[FIELD:2]*"
@ -61,7 +61,7 @@
{
"hint": "Phone Number",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*41[MASTER],001,[FIELD:1]*,[FIELD:2]*"
@ -160,7 +160,7 @@
{
"hint": "Days of Week (Sun=1, Sat=7 or #)",
"size": 7,
"hash": true
"alt": true
}
],
"dtmf": "*35[MASTER],[FIELD:1]*,[FIELD:2]*,[FIELD:3][FIELD:4]*,[FIELD:5][FIELD:6]*,[FIELD:7]*,[FIELD:8]*"

View file

@ -0,0 +1,162 @@
{
"params": {
"name": "Linear AE-100",
"ack": "#",
"begin": "0 + 2",
"size": 6
},
"opts": [
{
"title": "Add Resident to Directory",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Directory Code",
"size": 3
},
{
"hint": "Name",
"size": 16,
"alpha": "linear"
},
{
"hint": "Phone",
"size": 14
},
{
"hint": "Entry Code",
"size": 4
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,21#,[FIELD:2]#,[FIELD:3]#,[FIELD:4]#,[FIELD:5]#,[FIELD:5]#,99#"
},
{
"title": "Modify Resident in Directory",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Directory Code",
"size": 3
},
{
"hint": "Name",
"size": 16,
"alpha": "linear"
},
{
"hint": "Phone",
"size": 14
},
{
"hint": "Entry Code",
"size": 4
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,22#,[FIELD:2]#,[FIELD:3]#,[FIELD:4]#,[FIELD:5]#,99#"
},
{
"title": "Delete Resident from Directory",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Directory Code",
"size": 3
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,23#,[FIELD:2]#,[FIELD:2]#,99#"
},
{
"title": "Add Stand-Alone Entry Code",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Entry Code",
"size": 4
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,31#,[FIELD:2]#,[FIELD:2]#,99#"
},
{
"title": "Delete Stand-Alone Entry Code",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Entry Code",
"size": 4
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,33#,[FIELD:2]#,[FIELD:2]#,99#"
},
{
"title": "Change Welcome Display Text",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Line 1",
"size": 16,
"alpha": "linear"
},
{
"hint": "Line 2",
"size": 16,
"alpha": "linear"
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,57#,[FIELD:2]#,[FIELD:3]#,99#"
},
{
"title": "Latch Access Relay",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,81#,99#"
},
{
"title": "Release Access Relay",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,83#,99#"
}
]
}

View file

@ -0,0 +1,342 @@
{
"params": {
"name": "Linear AE-500",
"ack": "#",
"begin": "0 + 2",
"size": 6
},
"opts": [
{
"title": "Add Resident to Directory",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Directory Code",
"size": 3
},
{
"hint": "Name",
"size": 16,
"alpha": "linear"
},
{
"hint": "Phone",
"size": 14
},
{
"hint": "Entry Code",
"size": 4
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,21#,[FIELD:2]#,[FIELD:3]#,[FIELD:4]#,[FIELD:5]#,[FIELD:5]#,99#"
},
{
"title": "Modify Resident in Directory",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Directory Code",
"size": 3
},
{
"hint": "Name",
"size": 16,
"alpha": "linear"
},
{
"hint": "Phone",
"size": 14
},
{
"hint": "Entry Code",
"size": 4
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,22#,[FIELD:2]#,[FIELD:3]#,[FIELD:4]#,[FIELD:5]#,99#"
},
{
"title": "Delete Resident from Directory",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Directory Code",
"size": 3
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,23#,[FIELD:2]#,[FIELD:2]#,99#"
},
{
"title": "Add Entry Code",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Entry Code",
"size": 4
},
{
"hint": "Relay (1=A, 2=B, 3=AB, 4=A-ON/OFF 5=B-ON/OFF)",
"size": 1,
"min": 1,
"max": 5
},
{
"hint": "Number of Uses",
"size": 3,
"min": 1,
"max": 250,
"nozeros": true
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,31#,[FIELD:2]#,[FIELD:2]#,[FIELD:3]#,[FIELD:4],99#"
},
{
"title": "Modify Entry Code",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Entry Code",
"size": 4
},
{
"hint": "Relay (1=A, 2=B, 3=AB, 4=A-ON/OFF 5=B-ON/OFF)",
"size": 1,
"min": 1,
"max": 5
},
{
"hint": "Number of Uses",
"size": 3,
"min": 1,
"max": 250,
"nozeros": true
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,32#,[FIELD:2]#,[FIELD:3]#,[FIELD:4],99#"
},
{
"title": "Delete Entry Code",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Entry Code",
"size": 4
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,33#,[FIELD:2]#,[FIELD:2]#,99#"
},
{
"title": "Change Welcome Display Text",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Line 1",
"size": 16,
"alpha": "linear"
},
{
"hint": "Line 2",
"size": 16,
"alpha": "linear"
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,57#,[FIELD:2]#,[FIELD:3]#,99#"
},
{
"title": "Latch Access Relay",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Relay Channel: [A=1, B=2)",
"size": 1,
"min": 1,
"max": 2
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,8[FIELD:2]#,99#"
},
{
"title": "Release Access Relay",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Relay Channel: [A=1, B=2)",
"size": 1,
"min": 1,
"max": 2
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,8[FIELD:2]#,99#"
},
{
"title": "Assign Block Transmitter",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Number of Transmitters",
"size": 3,
"min": 1,
"max": 500
},
{
"hint": "Facility Code (0=None..15)",
"size": 2,
"min": 0,
"max": 15
},
{
"hint": "First/Lowest Transmitter ID",
"size": 2,
"min": 2,
"max": 6
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,41#,[FIELD:2]#,[FIELD:3]#,[FIELD:4]#,99#"
},
{
"title": "Assign Single Transmitter",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Facility Code (0=None..15)",
"size": 2,
"min": 0,
"max": 15
},
{
"hint": "Transmitter ID",
"size": 2,
"min": 2,
"max": 6
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,45#,[FIELD:2]#,[FIELD:3]#,99#"
},
{
"title": "Suspend Transmitter",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Facility Code (0=None..15)",
"size": 2,
"min": 0,
"max": 15
},
{
"hint": "Transmitter ID",
"size": 2,
"min": 2,
"max": 6
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,43#,[FIELD:2]#,[FIELD:3]#,99#"
},
{
"title": "Activate Transmitter",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Facility Code (0=None..15)",
"size": 2,
"min": 0,
"max": 15
},
{
"hint": "Transmitter ID",
"size": 2,
"min": 2,
"max": 6
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,42#,[FIELD:2]#,[FIELD:3]#,99#"
},
{
"title": "Delete Single Transmitter",
"fields": [
{
"hint": "Unit Number (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "Facility Code (0=None..15)",
"size": 2,
"min": 0,
"max": 15
},
{
"hint": "Transmitter ID",
"size": 2,
"min": 2,
"max": 6
}
],
"dtmf": "[FIELD:1]#,[MASTER]#,47#,[FIELD:2]#,[FIELD:3]#,99#"
}
]
}

View file

@ -12,6 +12,7 @@
<string name="error_invalid_dtmf">Invalid DTMF: <xliff:g id="type">%1$s</xliff:g></string>
<string name="error_invalid_field">Missing or invalid fields data.</string>
<string name="error_invalid_size">Invalid: <xliff:g id="size">%1$d</xliff:g> <xliff:g id="type">%2$s</xliff:g> required</string>
<string name="error_invalid">Invalid</string>
<string name="error_required">Required</string>
<string name="hint_master_code">Master Code</string>
<string name="hint_phone_number">Phone Number</string>