It is currently December 12th, 2019, 8:15 pm

Text Clock rmskin lua error

Help with creating, editing & fixing problems with skins
User avatar
Mor3bane
Posts: 655
Joined: May 7th, 2016, 7:32 am

Text Clock rmskin lua error

Mor3bane » December 3rd, 2019, 11:15 am

Hi @jsmorely

I identified this whilst looking into the behaviour of another topic I posted earlier - it occurred after a refresh and the weather returned a null value or no data from wxdata:

Code: Select all

Error Script: TextClock2.lua:195: attempt to compare nil with number
This also popped up next to the above - as an error previous to it but it is not repeating whereas the first error repeats continuously - with no wxdate to go on:

Code: Select all

Error RegExp matching error (-1) (TextClock\TextClock2.ini - [WeatherParent])
wondering what to do in the interim as I just work through some errors of my own (I can't lua)...
My DevArt Gallery

There are many ways to be different - there is only one way to be yourself
User avatar
balala
Rainmeter Sage
Posts: 9258
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Text Clock rmskin lua error

balala » December 3rd, 2019, 1:09 pm

Mor3bane wrote:
December 3rd, 2019, 11:15 am
wondering what to do in the interim
For first, post please a link to the skin. We have to replicate the error.
User avatar
Mor3bane
Posts: 655
Joined: May 7th, 2016, 7:32 am

Re: Text Clock rmskin lua error

Mor3bane » December 3rd, 2019, 1:38 pm

https://www.deviantart.com/jsmorley/art/TextClock3-Feb-5-2019-784453845

it is not intrinsic to th code - i live in a rural area and i wouldnt be surprised if the wxdata for our region was being updated by hand :rolmfao:

Perhaps just an error trap is needed rather than a fix...
My DevArt Gallery

There are many ways to be different - there is only one way to be yourself
User avatar
balala
Rainmeter Sage
Posts: 9258
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Text Clock rmskin lua error

balala » December 3rd, 2019, 1:53 pm

Mor3bane wrote:
December 3rd, 2019, 11:15 am
I identified this whilst looking into the behaviour of another topic I posted earlier - it occurred after a refresh and the weather returned a null value or no data from wxdata:

Code: Select all

Error Script: TextClock2.lua:195: attempt to compare nil with number
This also popped up next to the above - as an error previous to it but it is not repeating whereas the first error repeats continuously - with no wxdate to go on:

Code: Select all

Error RegExp matching error (-1) (TextClock\TextClock2.ini - [WeatherParent])
wondering what to do in the interim as I just work through some errors of my own (I can't lua)...
Something is not alright here. The posted error messages are related to the 2nd version of TextClock (Error Script: TextClock2.lua:195), but the link you've provided is a link to the 3rd version. So what version do you use?
User avatar
jsmorley
Developer
Posts: 19864
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Text Clock rmskin lua error

jsmorley » December 3rd, 2019, 1:53 pm

Mor3bane wrote:
December 3rd, 2019, 1:38 pm
https://www.deviantart.com/jsmorley/art/TextClock3-Feb-5-2019-784453845

it is not intrinsic to th code - i live in a rural area and i wouldnt be surprised if the wxdata for our region was being updated by hand :rolmfao:

Perhaps just an error trap is needed rather than a fix...
In the TextClock3.lua file, scroll down and find function TemperatureString()

Add this new line to it:
function TemperatureString()

tempUnit = measureUnits:GetStringValue()
tempValue = tonumber(measureTemperature:GetStringValue())
if not tempValue then return 'Error' end
That will stop the flooding of the log with the error about trying to evaluate a nil value as a number.
User avatar
Mor3bane
Posts: 655
Joined: May 7th, 2016, 7:32 am

Re: Text Clock rmskin lua error

Mor3bane » December 3rd, 2019, 2:00 pm

thanks jsmorely

the wxdata here can take sometimes up to 40 minutes before it updates from the time the skin updates with null values to the time it is reevaluated.

I probably wont even notice it for like a day at a time - but tonight things warped into noticing that error coincidentally.

Cheers for the fast reply.
My DevArt Gallery

There are many ways to be different - there is only one way to be yourself
User avatar
jsmorley
Developer
Posts: 19864
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Text Clock rmskin lua error

jsmorley » December 3rd, 2019, 2:13 pm

Mor3bane wrote:
December 3rd, 2019, 2:00 pm
thanks jsmorely

the wxdata here can take sometimes up to 40 minutes before it updates from the time the skin updates with null values to the time it is reevaluated.

I probably wont even notice it for like a day at a time - but tonight things warped into noticing that error coincidentally.

Cheers for the fast reply.
Here is a cleaner version of TextClock3.lua that will better handle missing weather information:

Code: Select all

function Initialize()

		measureUnits = SKIN:GetMeasure('UnitsChild')
		measureTemperature = SKIN:GetMeasure('TemperatureChild')
		measureConditions = SKIN:GetMeasure('ConditionsChild')
		
		afterText = SKIN:GetVariable('AfterText')
		untilText = SKIN:GetVariable('UntilText')
		halfText = SKIN:GetVariable('HalfText')
		
		dayTable = {}
		
		dayTable['0'] = ''
		dayTable['1'] = 'first'
		dayTable['2'] = 'second'
		dayTable['3'] = 'third'
		dayTable['4'] = 'fourth'
		dayTable['5'] = 'fifth'
		dayTable['6'] = 'sixth'
		dayTable['7'] = 'seventh'
		dayTable['8'] = 'eighth'
		dayTable['9'] = 'ninth'
		dayTable['10'] = 'tenth'
		dayTable['11'] = 'eleventh'
		dayTable['12'] = 'twelfth'
		dayTable['13'] = 'thirteenth'
		dayTable['14'] = 'fourteenth'
		dayTable['15'] = 'fifteenth'
		dayTable['16'] = 'sixteenth'
		dayTable['17'] = 'seventeenth'
		dayTable['18'] = 'eighteenth'
		dayTable['19'] = 'nineteenth'
		dayTable['20'] = 'twentieth'
		dayTable['30'] = 'thirtieth'
		
		numTable = {}
		
		numTable['0'] = 'zero'
		numTable['1'] = 'one'
		numTable['2'] = 'two'
		numTable['3'] = 'three'
		numTable['4'] = 'four'
		numTable['5'] = 'five'
		numTable['6'] = 'six'
		numTable['7'] = 'seven'
		numTable['8'] = 'eight'
		numTable['9'] = 'nine'
		numTable['10'] = 'ten'
		numTable['11'] = 'eleven'
		numTable['12'] = 'twelve'
		numTable['13'] = 'thirteen'
		numTable['14'] = 'fourteen'
		numTable['15'] = 'fifteen'
		numTable['16'] = 'sixteen'
		numTable['17'] = 'seventeen'
		numTable['18'] = 'eighteen'
		numTable['19'] = 'nineteen'
		numTable['20'] = 'twenty'
		numTable['30'] = 'thirty'
		numTable['40'] = 'forty'
		numTable['50'] = 'fifty'
		numTable['60'] = 'sixty'
		numTable['70'] = 'seventy'
		numTable['80'] = 'eighty'
		numTable['90'] = 'ninety'
		numTable['100'] = 'one hundred'

end

function Update()

	speakTime = TimeString()
	speakDate = DateString()
	speakConditions = ConditionsString()
	speakTemperature = TemperatureString()
	
	return speakTime .. ', ' .. speakDate .. '. ' .. speakConditions .. ', an ' .. speakTemperature

end

function TimeString()

	hour24 = tonumber(os.date('%H'))
	hour12 = tonumber(os.date('%I'))
	minute = tonumber(os.date('%M'))
	
	if hour24 < 12 then
		partOfDay = 'morning'
	elseif hour24 >= 12 and hour24 < 17 then
		partOfDay = 'afternoon'
	else
		partOfDay = 'evening'
	end
	
	if minute < 30 then
		adjustedMinute = minute
		midText = afterText
	elseif minute == 30 then
		adjustedMinute = minute
		midText = halfText
	else
		adjustedMinute = 60 - minute
		hour12 = hour12 == 12 and 1 or hour12 + 1
		midText = untilText		
	end

	if adjustedMinute >= 20 and adjustedMinute < 30 then 
		if adjustedMinute == 20 then
			minuteText = 'twenty'
		else
			minuteText = 'twenty'..'-'..numTable[tostring(adjustedMinute - 20)]
		end
	else
		if adjustedMinute < 10 then
			if adjustedMinute == 1 then
				minuteText = numTable[tostring(adjustedMinute)]..' minute'
			else
				minuteText = numTable[tostring(adjustedMinute)]..' minutes'
			end
		elseif adjustedMinute == 15 then
			minuteText = 'quarter'
		elseif adjustedMinute == 30 then
			minuteText = 'half'
		else
			minuteText = numTable[tostring(adjustedMinute)]
		end
	end

	if adjustedMinute == 0 then
		retString = 'it\'s '..numTable[tostring(hour12)]..' o\'clock'..' in the '..partOfDay
	else
		retString = 'it\'s '..minuteText.. ' '..midText..' '..numTable[tostring(hour12)]..' in the '..partOfDay
	end
	
	if hour24 == 12 and minute == 0 then
		retString = 'it\'s '..numTable[tostring(hour12)]..' o\'clock noon'
	end
	if hour24 == 0 and minute == 0 then
		retString = 'it\'s '..numTable[tostring(hour12)]..' o\'clock midnight'
	end
	
	SKIN:Bang('!SetOption', 'MeterTime', 'Text', retString)
	return retString

end

function DateString()

	weekdayName = os.date('%A')
	monthName = os.date('%B')
	
	dayNumber = os.date('%d')

	if tonumber(dayNumber) < 20 or tonumber(dayNumber) % 10 == 0 then
		dayText = dayTable[tostring(tonumber(dayNumber))]
	else
		dayLeft = string.sub(dayNumber, 1, 1) * 10
		dayRight = string.sub(dayNumber, 2)
		dayText = numTable[tostring(dayLeft)]..'-'..dayTable[dayRight]
	end
	
	SKIN:Bang('!SetOption', 'MeterDate', 'Text', 'on '..weekdayName..', the '..dayText..' of '..monthName)
	return 'on '..weekdayName..', the '..dayText..' of '..monthName
	
end

function ConditionsString()

	conditionsText = measureConditions:GetStringValue()
	if conditionsText == '' then
		SKIN:Bang('!SetOption', 'MeterConditions', 'Text', '')
		return ''
	end
	conditionsText = string.gsub(conditionsText, ' / ', ' and ')
	SKIN:Bang('!SetOption', 'MeterConditions', 'Text', 'the weather is '..conditionsText)
	return 'the weather is '..conditionsText

end

function TemperatureString()

	tempUnit = measureUnits:GetStringValue()
	tempValue = tonumber(measureTemperature:GetStringValue())
	if not tempValue then
		SKIN:Bang('!SetOption', 'MeterTemperature', 'Text', '')
		return ''
	end

	if tempUnit == 'C' then
		if tempValue > 31.7 then tempDesc = 'really hot'
			elseif tempValue > 26.1 then tempDesc = 'sort of hot'
			elseif tempValue > 15 then tempDesc = 'fairly warm'
			elseif tempValue > 9.4 then tempDesc = 'fairly cool'
			elseif tempValue > 0 then tempDesc = 'sort of chilly'
			else tempDesc = 'really cold'
		end
	end
	
	if tempUnit == 'F' then
		if tempValue > 89 then tempDesc = 'really hot'
			elseif tempValue > 79 then tempDesc = 'sort of hot'
			elseif tempValue > 59 then tempDesc = 'fairly warm'
			elseif tempValue > 49 then tempDesc = 'fairly cool'
			elseif tempValue > 32 then tempDesc = 'sort of chilly'
			else tempDesc = 'really cold'
		end
	end	
	
	if tempValue < 0 then
		tempValue = math.abs(tempValue)
		belowZero = 1
	else
		belowZero = 0
	end
	
	if tempValue > 100 then
		hundredText = 'one hundred and '
		tempValue = tempValue - 100
	else
		hundredText = ''
	end
	
	if tempValue < 20 or tempValue % 10 == 0 then
		tempText = numTable[tostring(tempValue)]
	else
		tempLeft = string.sub(tempValue, 1, 1) * 10
		tempRight = string.sub(tempValue, 2)
		tempText = numTable[tostring(tempLeft)]..'-'..numTable[tempRight]
	end
	
	if tempValue == 1 and hundredText == '' then 
		degreesText = ' degree'
	else
		degreesText = ' degrees'
	end
	
	if belowZero == 0 then
		SKIN:Bang('!SetOption', 'MeterTemperature', 'Text', 'it\'s '..tempDesc..' at '..hundredText..tempText..degreesText)
		return 'it\'s '..tempDesc..' at '..hundredText..tempText..degreesText
	else
		SKIN:Bang('!SetOption', 'MeterTemperature', 'Text', 'it\'s '..tempDesc..' at '..hundredText..tempText..degreesText..' below zero')
		return 'it\'s '..tempDesc..' at '..hundredText..tempText..degreesText..' below zero'
	end
	
end

So basically, if the weather "conditions" and "temperature" are missing, that entire bit is set to an empty string, the meters are set to empty strings, and just the date and time is displayed. No errors in the log are produced by the Lua, although you will still get the single regular expression error from WebParser. I wouldn't try to eliminate that, as you want some indication of why the weather isn't displaying.

Note that in the "conditions" routine, we are checking for an empty string from the skin measure, and reacting to that. In the "temperature" routine we first try to convert the temperature string from the skin measure to a number, and if that fails, the value will be "nil" or "nothing", since a number can never be an empty string. We then react to that nil value.

nil is a special type of value in Lua, which has two meanings that you can use various ways. It means both "doesn't exist" and "false".
User avatar
Mor3bane
Posts: 655
Joined: May 7th, 2016, 7:32 am

Re: Text Clock rmskin lua error

Mor3bane » December 3rd, 2019, 2:42 pm

jsmorley wrote:
December 3rd, 2019, 2:13 pm
Here is a cleaner version of TextClock3.lua that will better handle missing weather information:

Code: Select all

function Initialize()

		measureUnits = SKIN:GetMeasure('UnitsChild')
		measureTemperature = SKIN:GetMeasure('TemperatureChild')
		measureConditions = SKIN:GetMeasure('ConditionsChild')
		
		afterText = SKIN:GetVariable('AfterText')
		untilText = SKIN:GetVariable('UntilText')
		halfText = SKIN:GetVariable('HalfText')
		
		dayTable = {}
		
		dayTable['0'] = ''
		dayTable['1'] = 'first'
		dayTable['2'] = 'second'
		dayTable['3'] = 'third'
		dayTable['4'] = 'fourth'
		dayTable['5'] = 'fifth'
		dayTable['6'] = 'sixth'
		dayTable['7'] = 'seventh'
		dayTable['8'] = 'eighth'
		dayTable['9'] = 'ninth'
		dayTable['10'] = 'tenth'
		dayTable['11'] = 'eleventh'
		dayTable['12'] = 'twelfth'
		dayTable['13'] = 'thirteenth'
		dayTable['14'] = 'fourteenth'
		dayTable['15'] = 'fifteenth'
		dayTable['16'] = 'sixteenth'
		dayTable['17'] = 'seventeenth'
		dayTable['18'] = 'eighteenth'
		dayTable['19'] = 'nineteenth'
		dayTable['20'] = 'twentieth'
		dayTable['30'] = 'thirtieth'
		
		numTable = {}
		
		numTable['0'] = 'zero'
		numTable['1'] = 'one'
		numTable['2'] = 'two'
		numTable['3'] = 'three'
		numTable['4'] = 'four'
		numTable['5'] = 'five'
		numTable['6'] = 'six'
		numTable['7'] = 'seven'
		numTable['8'] = 'eight'
		numTable['9'] = 'nine'
		numTable['10'] = 'ten'
		numTable['11'] = 'eleven'
		numTable['12'] = 'twelve'
		numTable['13'] = 'thirteen'
		numTable['14'] = 'fourteen'
		numTable['15'] = 'fifteen'
		numTable['16'] = 'sixteen'
		numTable['17'] = 'seventeen'
		numTable['18'] = 'eighteen'
		numTable['19'] = 'nineteen'
		numTable['20'] = 'twenty'
		numTable['30'] = 'thirty'
		numTable['40'] = 'forty'
		numTable['50'] = 'fifty'
		numTable['60'] = 'sixty'
		numTable['70'] = 'seventy'
		numTable['80'] = 'eighty'
		numTable['90'] = 'ninety'
		numTable['100'] = 'one hundred'

end

function Update()

	speakTime = TimeString()
	speakDate = DateString()
	speakConditions = ConditionsString()
	speakTemperature = TemperatureString()
	
	return speakTime .. ', ' .. speakDate .. '. ' .. speakConditions .. ', an ' .. speakTemperature

end

function TimeString()

	hour24 = tonumber(os.date('%H'))
	hour12 = tonumber(os.date('%I'))
	minute = tonumber(os.date('%M'))
	
	if hour24 < 12 then
		partOfDay = 'morning'
	elseif hour24 >= 12 and hour24 < 17 then
		partOfDay = 'afternoon'
	else
		partOfDay = 'evening'
	end
	
	if minute < 30 then
		adjustedMinute = minute
		midText = afterText
	elseif minute == 30 then
		adjustedMinute = minute
		midText = halfText
	else
		adjustedMinute = 60 - minute
		hour12 = hour12 == 12 and 1 or hour12 + 1
		midText = untilText		
	end

	if adjustedMinute >= 20 and adjustedMinute < 30 then 
		if adjustedMinute == 20 then
			minuteText = 'twenty'
		else
			minuteText = 'twenty'..'-'..numTable[tostring(adjustedMinute - 20)]
		end
	else
		if adjustedMinute < 10 then
			if adjustedMinute == 1 then
				minuteText = numTable[tostring(adjustedMinute)]..' minute'
			else
				minuteText = numTable[tostring(adjustedMinute)]..' minutes'
			end
		elseif adjustedMinute == 15 then
			minuteText = 'quarter'
		elseif adjustedMinute == 30 then
			minuteText = 'half'
		else
			minuteText = numTable[tostring(adjustedMinute)]
		end
	end

	if adjustedMinute == 0 then
		retString = 'it\'s '..numTable[tostring(hour12)]..' o\'clock'..' in the '..partOfDay
	else
		retString = 'it\'s '..minuteText.. ' '..midText..' '..numTable[tostring(hour12)]..' in the '..partOfDay
	end
	
	if hour24 == 12 and minute == 0 then
		retString = 'it\'s '..numTable[tostring(hour12)]..' o\'clock noon'
	end
	if hour24 == 0 and minute == 0 then
		retString = 'it\'s '..numTable[tostring(hour12)]..' o\'clock midnight'
	end
	
	SKIN:Bang('!SetOption', 'MeterTime', 'Text', retString)
	return retString

end

function DateString()

	weekdayName = os.date('%A')
	monthName = os.date('%B')
	
	dayNumber = os.date('%d')

	if tonumber(dayNumber) < 20 or tonumber(dayNumber) % 10 == 0 then
		dayText = dayTable[tostring(tonumber(dayNumber))]
	else
		dayLeft = string.sub(dayNumber, 1, 1) * 10
		dayRight = string.sub(dayNumber, 2)
		dayText = numTable[tostring(dayLeft)]..'-'..dayTable[dayRight]
	end
	
	SKIN:Bang('!SetOption', 'MeterDate', 'Text', 'on '..weekdayName..', the '..dayText..' of '..monthName)
	return 'on '..weekdayName..', the '..dayText..' of '..monthName
	
end

function ConditionsString()

	conditionsText = measureConditions:GetStringValue()
	if conditionsText == '' then
		SKIN:Bang('!SetOption', 'MeterConditions', 'Text', '')
		return ''
	end
	conditionsText = string.gsub(conditionsText, ' / ', ' and ')
	SKIN:Bang('!SetOption', 'MeterConditions', 'Text', 'the weather is '..conditionsText)
	return 'the weather is '..conditionsText

end

function TemperatureString()

	tempUnit = measureUnits:GetStringValue()
	tempValue = tonumber(measureTemperature:GetStringValue())
	if not tempValue then
		SKIN:Bang('!SetOption', 'MeterTemperature', 'Text', '')
		return ''
	end

	if tempUnit == 'C' then
		if tempValue > 31.7 then tempDesc = 'really hot'
			elseif tempValue > 26.1 then tempDesc = 'sort of hot'
			elseif tempValue > 15 then tempDesc = 'fairly warm'
			elseif tempValue > 9.4 then tempDesc = 'fairly cool'
			elseif tempValue > 0 then tempDesc = 'sort of chilly'
			else tempDesc = 'really cold'
		end
	end
	
	if tempUnit == 'F' then
		if tempValue > 89 then tempDesc = 'really hot'
			elseif tempValue > 79 then tempDesc = 'sort of hot'
			elseif tempValue > 59 then tempDesc = 'fairly warm'
			elseif tempValue > 49 then tempDesc = 'fairly cool'
			elseif tempValue > 32 then tempDesc = 'sort of chilly'
			else tempDesc = 'really cold'
		end
	end	
	
	if tempValue < 0 then
		tempValue = math.abs(tempValue)
		belowZero = 1
	else
		belowZero = 0
	end
	
	if tempValue > 100 then
		hundredText = 'one hundred and '
		tempValue = tempValue - 100
	else
		hundredText = ''
	end
	
	if tempValue < 20 or tempValue % 10 == 0 then
		tempText = numTable[tostring(tempValue)]
	else
		tempLeft = string.sub(tempValue, 1, 1) * 10
		tempRight = string.sub(tempValue, 2)
		tempText = numTable[tostring(tempLeft)]..'-'..numTable[tempRight]
	end
	
	if tempValue == 1 and hundredText == '' then 
		degreesText = ' degree'
	else
		degreesText = ' degrees'
	end
	
	if belowZero == 0 then
		SKIN:Bang('!SetOption', 'MeterTemperature', 'Text', 'it\'s '..tempDesc..' at '..hundredText..tempText..degreesText)
		return 'it\'s '..tempDesc..' at '..hundredText..tempText..degreesText
	else
		SKIN:Bang('!SetOption', 'MeterTemperature', 'Text', 'it\'s '..tempDesc..' at '..hundredText..tempText..degreesText..' below zero')
		return 'it\'s '..tempDesc..' at '..hundredText..tempText..degreesText..' below zero'
	end
	
end

So basically, if the weather "conditions" and "temperature" are missing, that entire bit is set to an empty string, the meters are set to empty strings, and just the date and time is displayed. No errors in the log are produced by the Lua, although you will still get the single regular expression error from WebParser. I wouldn't try to eliminate that, as you want some indication of why the weather isn't displaying.

Note that in the "conditions" routine, we are checking for an empty string from the skin measure, and reacting to that. In the "temperature" routine we first try to convert the temperature string from the skin measure to a number, and if that fails, the value will be "nil" or "nothing", since a number can never be an empty string. We then react to that nil value.

nil is a special type of value in Lua, which has two meanings that you can use various ways. It means both "doesn't exist" and "false".
Awesome. Extra bits inserted - since I tweaked a bunch of textual stuff to fit my Aus temperature synonyms - 90F = "Fairly Warm" 60F = "Cool" :D
My DevArt Gallery

There are many ways to be different - there is only one way to be yourself
User avatar
jsmorley
Developer
Posts: 19864
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Text Clock rmskin lua error

jsmorley » December 3rd, 2019, 2:48 pm

Mor3bane wrote:
December 3rd, 2019, 2:42 pm
Awesome. Extra bits inserted - since I tweaked a bunch of textual stuff to fit my Aus temperature synonyms - 90F = "Fairly Warm" 60F = "Cool" :D
Good deal...
User avatar
Mor3bane
Posts: 655
Joined: May 7th, 2016, 7:32 am

Re: Text Clock rmskin lua error

Mor3bane » December 3rd, 2019, 9:36 pm

This is coming up now:

Code: Select all

Script: TextClock2.lua:77: attempt to concatenate global 'speakTemperature' (a nil value)
I checked the code mine matched yours - also - the wxdata is not returning a null value during this error catch. (afaik).
My DevArt Gallery

There are many ways to be different - there is only one way to be yourself