Archive

Archive for the ‘Uncategorized’ Category

NHTSA Recall #API using VIN numbers C# #VIN #ODI

The US Government maintains a vehicle safety recall list, in the event of a vehicle safety defect that requires vehicles to be recalled to the manufacturer for part replacement. This can be searched by make / model / year, but not currently by VIN.

We’ve just launched a Recall API based on VIN numbers, which is called in this format;

https://www.regcheck.org.uk/api/recalls.aspx/1FAFP34361W244896

Where 1FAFP34361W244896 is a 2001 Ford Focus that is under recall, the API requires basic authentication, and you can get a username and password by registering on the website http://www.vehicleregistrationapi.com/

JSON is returned in the following format;

{
   "Count":14,
   "Message":"Results returned successfully",
   "Results":[
      {
         "Manufacturer":"FORD MOTOR COMPANY",
         "NHTSACampaignNumber":"01V258000",
         "ReportReceivedDate":"\/Date(997243200000-0400)\/",
         "Component":"VISIBILITY:WINDSHIELD WIPER/WASHER:MOTOR",
         "Summary":"VEHICLE DESCRIPTION:  PASSENGER CARS, SPORT UTILITY VEHICLES, AND LIGHT AND MEDIUM DUTY PICKUP TRUCKS.   A SWITCH LOCATED IN THE PLASTIC COVER OF THE WIPER MOTOR GEAR CASE COULD MALFUNCTION AND OVERHEAT, POTENTIALLY RESULTING IN LOSS OF INTERMITTENT WIPER FUNCTION, LOSS OF WIPER PARK FUNCTION, COMPLETE LOSS OF WIPER FUNCTION, OR IGNITION OF THE PLASTIC COVER MATERIAL.  SWITCH MALFUNCTION IS MOST LIKELY TO OCCUR WHEN THE INTERMITTENT SETTING OF THE WIPERS IS BEING USED, OR WHEN SNOW OR ICE OBSTRUCTS THE BLADES FROM RETURNING TO THE \"PARKED\" POSITION AT THE BOTTOM OF THE WINDSHIELD.  THESE VEHICLES WERE BUILT AT THE FOLLOWING ASSEMBLY PLANTS:   ATLANTA PLANT FROM 2/11/00 THROUGH 7/31/00;  CHICAGO PLANT FROM 2/14/00 THROUGH 8/4/00;  KANSAS CITY PLANT FROM 2/26/00 TO 9/4/00;  KENTUCKY TRUCK PLANT FROM 2/18/00 TO 8/31/00;  MICHIGAN TRUCK PLANT FROM 2/23/00 THROUGH 8/3/00;  NORFOLK PLANT FROM 2/21/00 THROUGH 7/27/00;  WAYNE STAMPING AND ASSEMBLY PLANT FROM 2/25/00 THROUGH 8/15/00; AND WIXOM PLANT FROM 2/15/00 THROUGH 8/8/00.",
         "Conequence":"LOSS OF VISIBILITY WHILE DRIVING INCREASES THE RISK OF A CRASH.",
         "Remedy":"DEALERS WILL INSPECT THE DATE CODE ON THE WIPER MOTOR.  MOTORS BUILT WITH THE SUSPECT TIME FRAME WILL HAVE THE WIPER MOTOR GEAR CASE COVER REPLACED.  OWNER NOTIFICATION BEGAN AUGUST 20, 2001.  OWNERS WHO TAKE THEIR VEHICLES TO AN AUTHORIZED DEALER ON AN AGREED UPON SERVICE DATE AND DO NOT RECEIVE THE FREE REMEDY WITHIN A REASONABLE TIME SHOULD CONTACT FORD AT 1-866-436-7332.",
         "Notes":"ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236).",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"FORD MOTOR COMPANY",
         "NHTSACampaignNumber":"01V108000",
         "ReportReceivedDate":"\/Date(985755600000-0500)\/",
         "Component":"SEATS:FRONT ASSEMBLY:RECLINER",
         "Summary":"PM CERTAIN SEDANS AND WAGONS, THE SEAT BACK RECLINER HANDLE SPRING COULD HAVE BEEN DAMAGED DURING AN IN-PROCESS TEST AND THE OCCUPANT MAY NOTICE A CHUCKING, OR PERCEIVED LOOSENESS OF THE FRONT SEAT BACK, OR THE SEAT BACK COULD UNEXPECTEDLY RECLINE.",
         "Conequence":"IF THE SEAT BACK UNEXPECTEDLY RECLINES WHILE THE CAR IS BEING DRIVEN, IT COULD RESULT IN LOSS OF VEHICLE CONTROL.",
         "Remedy":"DEALERS WILL REPLACE THE SEAT BACK RECLINER HANDLE SPRING FOR THE DRIVER AND FRONT PASSENGER SEATS.  OWNER NOTIFICATION BEGAN APRIL 3, 2001.   OWNERS WHO TAKE THEIR VEHICLES TO AN AUTHORIZED DEALER ON AN AGREED UPON SERVICE DATE AND DO NOT RECEIVE THE FREE REMEDY WITHIN A REASONABLE TIME SHOULD CONTACT FORD AT 1-800-392-3673.",
         "Notes":"ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236).",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"FORD MOTOR COMPANY",
         "NHTSACampaignNumber":"01I017000",
         "ReportReceivedDate":"\/Date(1007010000000-0500)\/",
         "Component":"WHEELS:LUGS/NUTS/BOLTS",
         "Summary":"THIS IS NOT A SAFETY RECALL IN ACCORDANCE WITH THE SAFETY ACT.  HOWEVER, IT IS DEEMED A SAFETY IMPROVEMENT CAMPAIGN BY THE AGENCY.   VEHICLE DESCRIPTION:  2000-2001 FORD FOCUS PASSENGER VEHICLES, ORIGINALLY SOLD IN OR CURRENTLY REGISTERED IN THE STATES OF CONNECTICUT, DELAWARE, ILLINOIS, INDIANA, IOWA, KENTUCKY, MAINE, MARYLAND, MASSACHUSETTS, MICHIGAN, MINNESOTA, MISSOURI, NEW HAMPSHIRE, NEW JERSEY, NEW YORK, OHIOM, PENNSYLVANIA, RHODE ISLAND, VERMONT, WEST VIRGINIA, AND WISCONSIN.  IN HIGH CORROSION AREAS, WHERE SALT IS USED ON ROADWAYS IN THE WINTER, THE REAR WHEEL BEARING SEAL RACE CAN EXPERIENCE SURFACE CORROSION.  IF THIS CONDITION OCCURS, THE WHEEL BEARING SEALS COULD BECOME DAMAGED AND ALLOW CONTAMINATION TO ENTER THE WHEEL BEARINGS.",
         "Conequence":"THE WHEEL BEARINGS COULD PREMATURELY WEAR AND CAUSE A NOTICEABLE NOISE.  IF NOT REPAIRED, THIS CONDITION COULD PROGRESS TO THE POINT WHERE THE WHEEL BEGINS TO WOBBLE.",
         "Remedy":"DEALERS WILL REPLACE THE REAR WHEEL BEARINGS AT NO COST TO THE CONSUMER.  ADDITIONAL BEARING SEALS WILL ALSO BE INSTALLED TO ENSURE A SMOOTH RIDE.  THIS PROGRAM WILL BE IN EFFECT UNTIL DECEMBER 31, 2002, REGARDLESS OF MILEAGE.  EVEN IF THE VEHICLE HAS ALREADY BEEN SERVICED UNDER RECALL CAMPAIGN 00S31, FORD HAS TAKEN ADDITIONAL STEPS TO KEEP THE WHEEL BEARINGS IN TOP SHAPE.\r\nOWNERS CAN CONTACT FORD AT  1-866-436-7332, CONCERNING THIS PROGRAM.",
         "Notes":"FORD HAS DECIDED TO CONDUCT A SERVICE CAMPAIGN TO REPLACE THE REAR WHEEL BEARINGS.   OWNERS CAN CONTACT FORD AT  1-866-436-7332, CONCERNING THIS PROGRAM.",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"FORD MOTOR COMPANY",
         "NHTSACampaignNumber":"00V418000",
         "ReportReceivedDate":"\/Date(976770000000-0500)\/",
         "Component":"SEATS:FRONT ASSEMBLY:RECLINER",
         "Summary":"VEHICLE DESCRIPTION:  STATION WAGONS AND 3-DOOR VEHICLES.  THE SUBJECT VEHICLES HAVE A FOLDING 60/40 SECOND SEAT THAT BECOMES A LOAD FLOOR IN THE FOLDED POSITION. WHEN THE 60% PORTION OF THE SEAT IS FOLDED DOWN AND A LOAD IS APPLIED TO THE FRONT EDGE OF THE LOAD FLOOR, THE OUTBOARD HINGE PIVOT COULD DISENGAGE FROM THE HINGE.",
         "Conequence":"IF THE SEAT IS THEN RETURNED TO THE UPRIGHT POSITION WITHOUT RE-ENGAGING THE HINGE PIVOT, THE SEAT AND SEAT BELTS MAY NOT PROVIDE THE INTENDED LEVEL OF PERFORMANCE IN THE EVENT OF A CRASH.",
         "Remedy":"DEALERS WILL INSTALL A REVISED SEAT BACK HINGE PIVOT.",
         "Notes":"OWNER NOTIFICATION IBEGAN JANUARY 24, 2001.  OWNERS WHO TAKE THEIR VEHICLES TO AN AUTHORIZED DEALER ON AN AGREED UPON SERVICE DATE AND DO NOT RECEIVE THE FREE REMEDY WITHIN A REASONABLE TIME SHOULD CONTACT FORD AT 1-800-392-3673.  ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236).",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"FORD MOTOR COMPANY",
         "NHTSACampaignNumber":"02V288000",
         "NHTSAActionNumber":"EA02014 | PE02032",
         "ReportReceivedDate":"\/Date(1036558800000-0500)\/",
         "Component":"ELECTRICAL SYSTEM:12V/24V/48V BATTERY:CABLES | ELECTRICAL SYSTEM:12V/24V/48V BATTERY:CABLES",
         "Summary":"CERTAIN PASSENGER VEHICLES EQUIPPED WITH ZETEC ENGINES, LOOSE OR BROKEN ATTACHMENTS AND MISROUTED BATTERY CABLES COULD LEAD TO CABLE INSULATION DAMAGE.",
         "Conequence":"THIS, IN TURN, COULD CAUSE THE BATTERY CABLES TO SHORT RESULTING IN HEAT DAMAGE TO THE CABLES.  BESIDES HEAT DAMAGE, THE \"CHECK ENGINE\" LIGHT MAY ILLUMINATE, THE VEHICLE MAY FAIL TO START, OR SMOKE, MELTING, OR FIRE COULD ALSO OCCUR.",
         "Remedy":"DEALERS WILL INSPECT THE BATTERY CABLES FOR THE CONDITION OF THE CABLE INSULATION AND PROPER TIGHTENING OF THE TERMINAL ENDS.  AS NECESSARY, CABLES WILL BE REROUTED, RETAINING CLIPS INSTALLED, AND DAMAGED BATTERY CABLES REPLACED.   OWNER NOTIFICATION BEGAN FEBRUARY 10, 2003.   OWNERS WHO DO NOT RECEIVE THE FREE REMEDY  WITHIN A REASONABLE TIME SHOULD CONTACT FORD AT 1-866-436-7332.",
         "Notes":"ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236).",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"FORD MOTOR COMPANY",
         "NHTSACampaignNumber":"02V289000",
         "ReportReceivedDate":"\/Date(1036558800000-0500)\/",
         "Component":"STEERING:LINKAGES",
         "Summary":"CERTAIN PASSENGER VEHICLES HAVE LOOSE PINCH BOLTS THAT SECURE THE LOWER CONTROL ARM TO THE STEERING KNUCKLE HAVE BEEN REPORTED.",
         "Conequence":"LOOSE PINCH BOLTS COULD EXHIBIT NOISE, VIBRATION AND, IN EXTREME CASES IF LEFT UNCORRECTED, SEPARATION OF THE JOINT OR FRACTURE OF THE BALL JOINT STUD, INCREASING THE RISK OF A CRASH.",
         "Remedy":"DEALERS WILL INSPECT THE STEERING KNUCKLE PINCH BOLT FOR TIGHTNESS AND CORRECT AS NECESSARY.  OWNER NOTIFICATION BEGAN FEBRUARY 10, 2003.   OWNERS WHO DO NOT RECEIVE THE FREE REMEDY  WITHIN A REASONABLE TIME SHOULD CONTACT FORD AT 1-866-436-7332.",
         "Notes":"ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236).",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"FORD MOTOR COMPANY",
         "NHTSACampaignNumber":"03V482000",
         "NHTSAActionNumber":"EA02022",
         "ReportReceivedDate":"\/Date(1069218000000-0500)\/",
         "Component":"FUEL SYSTEM, GASOLINE",
         "Summary":"ON CERTAIN PASSENGER VEHICLES, CONTAMINATION OF THE FILTER IN THE FUEL DELIVERY MODULE (FDM) CAN REDUCE, AND EVENTUALLY BLOCK, THE FLOW OF FUEL TO THE ENGINE.",
         "Conequence":"THIS MAY CAUSE ENGINE HESITATION, LOSS OF POWER, SURGING, AND OTHER SIMILAR  SYMPTOMS.  OVER TIME, THE FILTER MAY BECOME SUFFICIENTLY BLOCKED TO CAUSE THE ENGINE TO STALL, WHICH COULD RESULT IN A CRASH.",
         "Remedy":"THIS ACTION IS DEEMED A SAFETY IMPROVEMENT CAMPAIGN AND IS NOT BEING CONDUCTED UNDER THE SAFETY ACT.  ALL OWNERS WILL BE NOTIFIED OF THE PROBLEM, AND DEALERS WILL REPLACE THE FDM WITH A NEW DESIGN AT NO CHARGE IF THE OWNER REPORTS THAT THE VEHICLE EXHIBITS ANY OF THE IDENTIFIED SYMPTOMS.  THE FREE REPLACEMENT WILL BE AVAILABLE FOR A PERIOD OF 10 YEARS FOLLOWING THE ORIGINAL PURCHASE OF THE VEHICLE, WITH NO MILEAGE LIMIT.  OWNER NOTIFICATION IS EXPECTED TO BEGIN DURING NOVEMBER 2003.  OWNERS SHOULD CONTACT FORD AT 1-800-392-3673.",
         "Notes":"FORD CAMPAIGN NO. 03N01.  CUSTOMERS CAN ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236).",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"FORD MOTOR COMPANY",
         "NHTSACampaignNumber":"05V030000",
         "NHTSAActionNumber":"EA04023",
         "ReportReceivedDate":"\/Date(1107234000000-0500)\/",
         "Component":"LATCHES/LOCKS/LINKAGES:DOORS:LATCH",
         "Summary":"CERTAIN PASSENGER VEHICLES WITH FOUR OR FIVE DOORS AND ORIGINALLY SOLD IN OR CURRENTLY REGISTERED IN CONNECTICUT, DELAWARE, ILLINOIS, INDIANA, IOWA, MAINE, MARYLAND, MASSACHUSETTS, MICHIGAN, MINNESOTA, MISSOURI, NEW HAMPSHIRE, NEW JERSEY, NEW YORK, OHIO, PENNSYLVANIA, RHODE ISLAND, VERMONT, WEST VIRGINIA, WISCONSIN, AND THE DISTRICT OF COLUMBIA, A BUILD-UP OF CORROSION AT THE PAWL PIVOT AREA OF THE REAR DOOR LATCH CAN CAUSE A BINDING CONDITION OF THE PAWL THAT MAY AFFECT PROPER ENGAGEMENT OF THE PAWL INTO THE CATCH. THE OCCUPANT MAY EXPERIENCE DIFFICULTY OPENING OR CLOSING A REAR DOOR, AND EVENTUALLY THE REAR DOOR MAY NOT LATCH PROPERLY. \r\n",
         "Conequence":"IF NOT LATCHED PROPERLY, THE DOOR MAY OPEN WHILE THE VEHICLE IS IN MOTION.  IF AN OCCUPANT FELL OUT OF THE VEHICLE, PERSONAL INJURIES COULD OCCUR.",
         "Remedy":"DEALERS WILL HAVE A LOWER ROCKER SEAL ADDED TO THE DOOR AND HAVE THE REAR DOOR LATCHES EVALUATED FREE OF CHARGE.  A LATCH THAT PASSES THE EVALUATION WILL BE LUBRICATED TO PREVENT FUTURE CORROSION.  A LATCH THAT DOES NOT PASS THE EVALUATION WILL BE REPLACED.  IN ADDITION, A STICKER WILL BE AFFIXED TO THE REAR DOORS ADVISING THE OWNERS TO USE THE RECOMMENDED LUBRICANT.  THE RECALL BEGAN ON MARCH 9, 2005.  OWNERS MAY CONTACT FORD AT 1-800-392-3673.\r\n",
         "Notes":"FORD RECALL NO. 05S27.    CUSTOMERS MAY ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S VEHICLE SAFETY HOTLINE AT 1-888-327-4236 (TTY 1-800-424-9153), OR GO TO HTTP://WWW.SAFERCAR.GOV. ",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"PRO-A MOTORS, INC.",
         "NHTSACampaignNumber":"06E026000",
         "ReportReceivedDate":"\/Date(1143090000000-0500)\/",
         "Component":"EXTERIOR LIGHTING",
         "Summary":"CERTAIN PRO-A MOTORS CORNER LAMPS, TURN SIGNALS, AND HEADLIGHTS SOLD AS REPLACEMENT LAMPS FOR USE ON CERTAIN PASSENGER VEHICLES LISTED ABOVE.  SOME COMBINATION LAMPS THAT ARE NOT EQUIPPED WITH AMBER SIDE REFLECTORS FAIL TO CONFORM TO FEDERAL MOTOR VEHICLE SAFETY STANDARD NO. 108, LAMPS, REFLECTIVE DEVICES, AND ASSOCIATED EQUIPMENT.",
         "Conequence":"WITHOUT THE AMBER REFLECTORS, THE VEHICLE WILL BE POORLY ILLUMINATED, POSSIBLY RESULTING IN A VEHICLE CRASH WITHOUT WARNING.",
         "Remedy":"PRO-A MOTORS WILL NOTIFY OWNERS AND OFFER TO REPURCHASE THE LAMPS.  THE RECALL BEGAN ON APRIL 3, 2006.  OWNERS MAY CONTACT PRO-A MOTORS AT 323-838-2988.",
         "Notes":"THIS RECALL ONLY PERTAINS TO PRO-A MOTORS AFTERMARKET LAMPS AND HAS NO RELATION TO ANY ORIGINAL EQUIPMENT INSTALLED ON THE LISTED PASSENGER VEHICLES.  FOR MORE INFORMATION ON THE LAMP MODEL NUMBERS, CLICK ON DOCUMENT SEARCH AND VIEW DOCUMENT TITLED \"LAMP MODEL NUMBERS.\"  CUSTOMERS MAY CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S VEHICLE SAFETY HOTLINE AT 1-888-327-4236 (TTY: 1-800-424-9153); OR GO TO HTTP://WWW.SAFERCAR.GOV.",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"CK MOTORSPORT, INC.",
         "NHTSACampaignNumber":"06E049000",
         "ReportReceivedDate":"\/Date(1148443200000-0400)\/",
         "Component":"EXTERIOR LIGHTING",
         "Summary":"CERTAIN CK MOTORSPORTS COMBINATION HEADLIGHTS, CLEAR CORNER, BUMPER, AND SIDE MARKER LIGHTS SOLD AS REPLACEMENT LAMPS FOR USE ON THE PASSENGER VEHICLES LISTED ABOVE.  SOME COMBINATION LAMPS THAT ARE NOT EQUIPPED WITH AMBER SIDE REFLECTORS FAIL TO CONFORM TO FEDERAL MOTOR VEHICLE SAFETY STANDARD NO. 108, LAMPS, REFLECTIVE DEVICES, AND ASSOCIATED EQUIPMENT.",
         "Conequence":"WITHOUT THE AMBER REFLECTORS, THE VEHICLE WILL BE POORLY ILLUMINATED, POSSIBLY RESULTING IN A VEHICLE CRASH WITHOUT WARNING.",
         "Remedy":"CK MOTORSPORT WILL NOTIFY OWNERS AND REPLACE THE NONCOMPLIANT LAMPS FREE OF CHARGE.  THE RECALL BEGAN ON JULY 1, 2006.  OWNERS MAY CONTACT CK MOTORSPORT AT 1-909-610-7211.",
         "Notes":"THIS RECALL ONLY PERTAINS TO AFTERMARKET REPLACEMENT EQUIPMENT AND HAS NO RELATION TO ANY ORIGINAL EQUIPMENT INSTALLED ON VEHICLES MANUFACTURED BY THE VEHICLE MANUFACTURERS.  FOR MORE INFORMATION ON THE LAMP MODEL NUMBERS, CLICK ON DOCUMENT SEARCH AND VIEW DOCUMENT TITLED \"LAMP MODEL NUMBERS.\"  CUSTOMERS MAY CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S VEHICLE SAFETY HOTLINE AT 1-888-327-4236 (TTY: 1-800-424-9153); OR GO TO HTTP://WWW.SAFERCAR.GOV.\r\n",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"K2 MOTOR CORPORATION",
         "NHTSACampaignNumber":"08E050000",
         "ReportReceivedDate":"\/Date(1218427200000-0400)\/",
         "Component":"EXTERIOR LIGHTING:HEADLIGHTS",
         "Summary":"K2 MOTOR IS RECALLING 1,921 AFTERMARKET HEADLAMPS OF VARIOUS MODELS SOLD FOR USE ON THE ABOVE LISTED VEHICLES.  THESE HEADLAMPS ARE MISSING THE AMBER SIDE REFLEX REFLECTOR WHICH FAILS TO CONFORM WITH THE REQUIREMENTS OF FEDERAL MOTOR VEHICLE SAFETY STANDARD NO. 108, \"LAMPS, REFLECTIVE DEVICES, AND ASSOCIATED EQUIPMENT.\"",
         "Conequence":"WITHOUT THE AMBER SIDE REFLEX REFLECTORS, THE LIGHTING VISIBILITY MAY BE AFFECTED, POSSIBLY RESULTING IN A VEHICLE CRASH.",
         "Remedy":"K2 MOTOR WILL NOTIFY OWNERS AND OFFER A FULL REFUND.  THE RECALL BEGAN ON DECEMEBER 17, 2008.  OWNERS MAY CONTACT K2 MOTOR AT 1-909-839-2992.",
         "Notes":"THIS RECALL ONLY PERTAINS TO AFTERMARKET REPLACEMENT EQUIPMENT AND HAS NO RELATION TO ANY ORIGINAL EQUIPMENT INSTALLED ON VEHICLES MANUFACTURED BY HONDA, FORD, OR CHRYSLER LLC.   CUSTOMERS MAY CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S VEHICLE SAFETY HOTLINE AT 1-888-327-4236 (TTY: 1-800-424-9153); OR GO TO HTTP://WWW.SAFERCAR.GOV.",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"SABERSPORT",
         "NHTSACampaignNumber":"09E012000",
         "ReportReceivedDate":"\/Date(1239076800000-0400)\/",
         "Component":"EXTERIOR LIGHTING",
         "Summary":"SABERSPORT IS RECALLING 16,270 COMBINATION CORNER AND BUMPER LAMP ASSEMBLIES OF VARIOUS PART NUMBERS SOLD FOR USE AS AFTERMARKET EQUIPMENT FOR VARIOUS PASSENGER VEHICLES.  THESE HEADLAMPS FAIL TO CONFORM TO THE REQUIREMENTS OF FEDERAL MOTOR VEHICLE SAFETY STANDARD NO. 108, \"LAMPS, REFLECTIVE DEVICES, AND ASSOCIATED EQUIPMENT.\"  THESE LAMPS DO NOT CONTAIN THE REQUIRED AMBER SIDE REFLECTORS.",
         "Conequence":"DECREASED LIGHTING VISIBILITY MAY RESULT IN A VEHICLE CRASH.",
         "Remedy":"SABERSPORT WILL NOTIFY OWNERS AND OFFER A FULL REFUND FOR THE NONCOMPLIANT COMBINATION LAMPS.  THE SAFETY RECALL BEGAN ON MAY 11, 2009.  OWNERS MAY CONTACT SABERSPORT AT 1-909-598-7589.  ",
         "Notes":"THIS RECALL ONLY PERTAINS TO AFTERMARKET REPLACEMENT EQUIPMENT AND HAS NO RELATION TO ANY ORIGINAL EQUIPMENT INSTALLED ON VEHICLES PRODUCED BY THE VEHICLE MANUFACTURER.  IN ORDER TO DETERMINE IF YOUR AFTERMARKET LAMP ASSEMBLY IS AFFECTED BY THIS NONCOMPLIANCE, PLEASE REVIEW THE LIST OF MODEL NUMBERS PROVIDED TO US BY SABERSPORT.  THE LIST CAN BE FOUND UNDER \"DOCUMENT SEARCH\" LOCATED AT THE BOTTOM OF YOUR SCREEN.  OWNERS MAY ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S VEHICLE SAFETY HOTLINE AT 1-888-327-4236 (TTY 1-800-424-9153), OR GO TO <A HREF=HTTP://WWW.SAFERCAR.GOV>HTTP://WWW.SAFERCAR.GOV</A> .",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"DOPE, INC.",
         "NHTSACampaignNumber":"09E025000",
         "ReportReceivedDate":"\/Date(1242014400000-0400)\/",
         "Component":"EXTERIOR LIGHTING:HEADLIGHTS",
         "Summary":"DOPE, INC. IS RECALLING 42,540 COMBINATION CORNER AND BUMPER LAMP ASSEMBLIES OF VARIOUS PART NUMBERS SOLD FOR USE AS AFTERMARKET EQUIPMENT FOR VARIOUS PASSENGER VEHICLES.  THESE HEADLAMPS FAIL TO CONFORM TO THE REQUIREMENTS OF FEDERAL MOTOR VEHICLE SAFETY STANDARD NO. 108, \"LAMPS, REFLECTIVE DEVICES, AND ASSOCIATED EQUIPMENT.\"  THESE LAMPS DO NOT CONTAIN THE REQUIRED AMBER SIDE REFLECTORS.",
         "Conequence":"DECREASED LIGHTING VISIBILITY MAY RESULT IN A VEHICLE CRASH.",
         "Remedy":"DOPE, INC. WILL NOTIFY OWNERS AND OFFER A FULL REFUND FOR THE NONCOMPLIANT COMBINATION LAMPS.  THE SAFETY RECALL BEGAN ON JULY 28, 2009.  OWNERS MAY CONTACT DOPE, INC. AT 1-626-272-1798.  ",
         "Notes":"THIS RECALL ONLY PERTAINS TO AFTERMARKET REPLACEMENT EQUIPMENT AND HAS NO RELATION TO ANY ORIGINAL EQUIPMENT INSTALLED ON VEHICLES PRODUCED BY THE VEHICLE MANUFACTURER.  IN ORDER TO DETERMINE IF YOUR AFTERMARKET LAMP ASSEMBLY IS AFFECTED BY THIS NONCOMPLIANCE, PLEASE REVIEW THE LIST OF MODEL NUMBERS PROVIDED TO US BY DOPE, INC.  THE LIST CAN BE FOUND UNDER \"DOCUMENT SEARCH\" LOCATED AT THE BOTTOM OF YOUR SCREEN.   \r\nOWNERS MAY ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S VEHICLE SAFETY HOTLINE AT 1-888-327-4236 (TTY 1-800-424-9153), OR GO TO <A HREF=HTTP://WWW.SAFERCAR.GOV>HTTP://WWW.SAFERCAR.GOV</A> .",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      },
      {
         "Manufacturer":"RIDE CONTROL, LLC",
         "NHTSACampaignNumber":"12E007000",
         "ReportReceivedDate":"\/Date(1330059600000-0500)\/",
         "Component":"EQUIPMENT",
         "Summary":"RIDE CONTROL, LLC (RIDE CONTROL) IS RECALLING CERTAIN READYMOUNT ASSEMBLIES, P/N 746641MT AND 746646MT, WITH CORRESPONDING AFTERMARKET CUSTOMER PART NUMBERS: GABRIEL G56944 AND GABRIEL G56945, AND PRIVATELY BRANDED PARTSMASTER WITH PART NUMBERS G68944 AND G68945.  THE READYMOUNT ASSEMBLIES WERE SOLD AS AFTERMARKET SERVICE EQUIPMENT FOR USE ON CERTAIN 2000 THROUGH 2005 FORD FOCUS VEHICLES.  THESE ASSEMBLIES WERE ASSEMBLED WITH A NUT WITHOUT THE NECESSARY WASHER.  THE ABSENCE OF THE WASHER CAN ALLOW THE READYMOUNT ASSEMBLY TO PULL APART THE TOP MOUNT.",
         "Conequence":"IF THE ASSEMBLY SEPARATES DURING INSTALLATION, IT COULD RESULT IN INJURY TO THE INSTALLER.  IF THE ASSEMBLY SEPARATES WHILE THE VEHICLE IS IN MOTION, IT COULD RESULT IN SECONDARY DAMAGE TO THE VEHICLE AND POSSIBLY RESULT IN A VEHICLE CRASH.",
         "Remedy":"RIDE CONTROL WILL NOTIFY OWNERS AND WILL SET UP PROCEDURES TO INSPECT, REPAIR, AND/OR REPLACE THE AFFECTED PARTS WITHOUT CHARGE TO THE OWNER.  THE SAFETY RECALL BEGAN ON MARCH 30, 2012.  OWNERS MAY CONTACT RIDE CONTROL AT 1-800-999-3903.",
         "Notes":"OWNERS MAY ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S VEHICLE SAFETY HOTLINE AT 1-888-327-4236 (TTY 1-800-424-9153), OR GO TO <A HREF=HTTP://WWW.SAFERCAR.GOV>HTTP://WWW.SAFERCAR.GOV</A> .",
         "ModelYear":"2001",
         "Make":"FORD",
         "Model":"FOCUS"
      }
   ]
}
Categories: Uncategorized

AWS #Transcribe Speech to Text using C#

AWS has a transcribe service which converts audio containing speech to text. It is very tightly integrated with the AWS ecosystem, so it’s probably best used for systems that are already using AWS for other services – specifically, S3 for storage of audio, and perhaps Cloudwatch and Lambda for post processing.

So, the Transcribe service takes an audio file that is already in an S3 bucket with Amazon, and produces text output, which is placed in another bucket. The process is asynchronous, so it’s best to have another event (i.e. Cloudwatch + Lambda) dealing with the output.

First off, you need the Nuget package “Install-Package AWSSDK.TranscribeService” installed for your project. You should also have your local dev environment setup to access AWS via the CLI (aws configure). You don’t have to do that last step, but the code below assumes you have done this.

var client = new AmazonTranscribeServiceClient( RegionEndpoint.EUWest1);

var job = client.StartTranscriptionJobAsync(new StartTranscriptionJobRequest
{
	LanguageCode = LanguageCode.EnUS,
	Media = new Media
	{
		MediaFileUri = "s3://audioBucket/message.mp3"
	},
	MediaFormat = MediaFormat.Mp3,
	OutputBucketName = "aws.serverless.2",
	TranscriptionJobName = "message"
}).Result;

Here, we specify the input S3 Uri, which is an Mp3 file, in US English. I also specify the output bucket, and the name of the file.

This will run, and return immediately. At some time in the future, a file will appear in the output bucket with contents such as;

{
   "jobName":"hotline2",
   "accountId":"005445879168",
   "results":{
      "transcripts":[
         {
            "transcript":"thank you for Collins in his bank, the first American bank designed for international customers. Please leave your message and we will return your call shortly."
         }
      ],
      "items":[
         {
            "start_time":"0.44",
            "end_time":"0.79",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"thank"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"0.79",
            "end_time":"0.88",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"you"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"0.88",
            "end_time":"1.01",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"for"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"1.01",
            "end_time":"1.52",
            "alternatives":[
               {
                  "confidence":"0.9214",
                  "content":"Collins"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"1.52",
            "end_time":"1.65",
            "alternatives":[
               {
                  "confidence":"0.9884",
                  "content":"in"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"1.65",
            "end_time":"1.82",
            "alternatives":[
               {
                  "confidence":"0.9662",
                  "content":"his"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"1.82",
            "end_time":"2.48",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"bank"
               }
            ],
            "type":"pronunciation"
         },
         {
            "alternatives":[
               {
                  "confidence":"0.0",
                  "content":","
               }
            ],
            "type":"punctuation"
         },
         {
            "start_time":"2.51",
            "end_time":"2.77",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"the"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"2.78",
            "end_time":"3.12",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"first"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"3.12",
            "end_time":"3.63",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"American"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"3.63",
            "end_time":"3.99",
            "alternatives":[
               {
                  "confidence":"0.996",
                  "content":"bank"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"4.0",
            "end_time":"4.58",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"designed"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"4.58",
            "end_time":"4.74",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"for"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"4.74",
            "end_time":"5.39",
            "alternatives":[
               {
                  "confidence":"0.9987",
                  "content":"international"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"5.39",
            "end_time":"6.16",
            "alternatives":[
               {
                  "confidence":"0.9995",
                  "content":"customers"
               }
            ],
            "type":"pronunciation"
         },
         {
            "alternatives":[
               {
                  "confidence":"0.0",
                  "content":"."
               }
            ],
            "type":"punctuation"
         },
         {
            "start_time":"6.54",
            "end_time":"6.94",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"Please"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"6.94",
            "end_time":"7.12",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"leave"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"7.12",
            "end_time":"7.26",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"your"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"7.26",
            "end_time":"7.86",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"message"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"7.87",
            "end_time":"8.06",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"and"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"8.06",
            "end_time":"8.17",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"we"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"8.17",
            "end_time":"8.36",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"will"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"8.36",
            "end_time":"8.78",
            "alternatives":[
               {
                  "confidence":"0.5229",
                  "content":"return"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"8.78",
            "end_time":"8.95",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"your"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"8.95",
            "end_time":"9.33",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"call"
               }
            ],
            "type":"pronunciation"
         },
         {
            "start_time":"9.34",
            "end_time":"10.05",
            "alternatives":[
               {
                  "confidence":"1.0",
                  "content":"shortly"
               }
            ],
            "type":"pronunciation"
         },
         {
            "alternatives":[
               {
                  "confidence":"0.0",
                  "content":"."
               }
            ],
            "type":"punctuation"
         }
      ]
   },
   "status":"COMPLETED"
}

As you can see from the result, it can make some errors, for example, here it used the world “Collins” instead of “Calling”, so the process is not perfect. However, the word-by-word breakdown is really useful, for any other post-processing you may want to do.

This would be excellent for generating subtitles from movie audio, for example.

Categories: Uncategorized

Using #Delphi to call a JSON based #API with basic authentication.

Delphi is quite an old programming language, and has been around since 1995. It’s not really one of the “cool kids” when it comes to programming. However, there is nothing stopping it interoperating with modern REST APIs, which this blog post will show.

So, first off, I downloaded the community edition of Delphi from Embarcadero, and started, directly after a “Hello World”, to make a request to a service that returns my external IP address. Just a simple HTTP GET, but that’s the first step.

So far so simple. I make a crazy call out to CoInitializeEx which does some COM initialization (COM – oh dear). Anyway, then I create a TidHTTP object, which comes from the Indy Project (https://www.indyproject.org/) and then makes a simple GET request, and prints the output to console.

In the above example, I am using an API from http://www.placaapi.com/ – which is a Brazilian vehicle lookup service. you need a username and password, which can be obtained free of charge from the website.

I create an Authentication object, and set the username and password, then I make a HTTP GET request as before.

After I receive the JSON, I pass this to TJSonObject, and read the Description Node from the JSON – There are plenty more fields here, but this is the easiest to display.

For those who want to copy/paste the code – it’s below;

program helloWorld;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  SysUtils, IdHTTP, ActiveX, IdAuthentication, System.JSON;

var
  HTTP: TIdHTTP;  // Create the Indy HTTP Library https://www.indyproject.org/
  Buffer: String;
  JSonValue:TJSonValue;
  Description: string;
  Registration: string;

begin
  try
    // Enter the car registration here
    Registration :=  'BYP6404';
    // https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex
    CoInitializeEx(nil, COINIT_MULTITHREADED);
    HTTP := TIdHTTP.Create;
    HTTP.Request.BasicAuthentication:= true;
    HTTP.Request.Authentication := TIdBasicAuthentication.Create;
    HTTP.Request.Authentication.Username := '***USERNAME HERE***';
    HTTP.Request.Authentication.Password := '***PASSWORD HERE***';
    // Below is the API endpoint for Brazil, can be replaced with any country.
    Buffer := HTTP.Get('http://www.placaapi.com/api/json.aspx/CheckBrazil/' + Registration);
    //Writeln(Buffer); // Uncomment to see full result
    JsonValue := TJSonObject.ParseJSONValue(Buffer);
    // Read the Vehicle Decription
    Description := JsonValue.GetValue<string>('Description');
    Writeln(Description);
  except
    on E: Exception do
        Writeln(E.ClassName, ': ', E.Message); // Show any error
  end;
  readln; // pause on completion
end.

Categories: Uncategorized

Getting #AWS #Lambda timeout value at runtime in C#

If you have a Lambda function in C#, and you have a process that must complete before Amazon kills the process, say in the classic bank transfer example, where you debit one account and credit another. Both actions need to be taken atomically, or else the process should be rolled back.

In this case, you can’t have AWS killing your lambda function due to lack of time remaining, in mid-transaction. In this case, you’d have one account missing money, and no money in the payee account. In this case, it would be better to get a forewarning, that gives you X seconds to rollback the transaction, so that at least, you’re back to where you started.

So, what’s the magic command:

     var context = (ILambdaContext) HttpContext.Items["LambdaContext"];

This gives you an ILambdaContext Object, that contains data similar to the following;


{
   "FunctionName":"HelloWorld-AspNetCoreFunction-1T4MMT4XYY3IJ",
   "FunctionVersion":"$LATEST",
   "LogGroupName":"/aws/lambda/HelloWorld-AspNetCoreFunction-1T4MMT4XYY3IJ",
   "LogStreamName":"2021/03/01/[$LATEST]36833c138ec040549dfd7aa350f2ca44",
   "MemoryLimitInMB":512,
   "AwsRequestId":"b481c563-a027-43d7-bb8e-841ea0f89cdf",
   "InvokedFunctionArn":"arn:aws:lambda:eu-west-1:005445879168:function:HelloWorld-AspNetCoreFunction-1T4MMT4XYY3IJ",
   "RemainingTime":"00:00:28.6830000",
   "ClientContext":null,
   "Identity":{
      "IdentityId":"",
      "IdentityPoolId":""
   },
   "Logger":{
      
   }
}

Which gives you Remaining Time , and the Memory Limit, along with other values.

For other values relating to the Lambda, you should also check the Environment variables in your code.

Categories: Uncategorized

Bypass Google #Recaptcha using #CapMonster

Google Recaptcha is a system that is designed to stop bots from interacting with a website, and only allow humans. However, with everything, there is always a workaround. In this demo I’m using CapMonster’s API, which works, but in my opinion is quite slow, here a sample request takes 52 seconds. So probably unsuited to real-time processing.

I used the Nuget Package created by “Mohammed Boukhlouf” https://github.com/M-Boukhlouf/CapMonsterCloud and the full source is here; https://github.com/infiniteloopltd/CapMonsterDemo – without my client ID of course.

Here is the jist of the code;

var start = DateTime.Now;
var client = new CapMonsterClient(secret);
var captchaTask = new RecaptchaV3TaskProxyless
{
WebsiteUrl = "https://lessons.zennolab.com/captchas/recaptcha/v3.php?level=beta",
WebsiteKey = "6Le0xVgUAAAAAIt20XEB4rVhYOODgTl00d8juDob",
MinScore = 0.3,
PageAction = "myverify"
};
// Create the task and get the task id
var taskId = client.CreateTaskAsync(captchaTask).Result;
Console.WriteLine("Created task id : " + taskId);
var solution = client.GetTaskResultAsync<RecaptchaV3TaskProxylessResult>(taskId).Result;
// Recaptcha response to be used in the form
var recaptchaResponse = solution.GRecaptchaResponse;

Console.WriteLine("Solution : " + recaptchaResponse);
var web = new WebClient {Encoding = Encoding.UTF8};
web.Headers.Add("content-type","application/x-www-form-urlencoded");
var result = web.UploadString("https://lessons.zennolab.com/captchas/recaptcha/v3_verify.php?level=beta", "token=" + recaptchaResponse);
var idxStart = result.IndexOf("<pre>", StringComparison.Ordinal);
var idxEnd = result.IndexOf("</pre>", StringComparison.Ordinal);
var jsonResult = result.Substring(idxStart, idxEnd - idxStart);
Console.WriteLine(jsonResult);
var end = DateTime.Now;
var duration = end-start;
Console.WriteLine(duration.TotalSeconds);

Categories: Uncategorized

Optimizing index_merge in #MySQL for performance

If you have a query in MySQL that uses an index merge, i.e. that is you are querying on multiple unconnected indexes on the same table, here is a performance tweak, that in my case changed a query from 40 seconds to 0.254 seconds, by reorganising the query with a subquery.

So, My original query was like this:

SELECT *
FROM   data
WHERE  ( l1 = 'no-match' )
        OR ( l2 = 'X'
             AND ( f1 = 'Y'
                    OR p = 'Z' ) ) 

Where “No-Match” is value that didn’t match anything in the table, and X,Y,Z were values that did match something. In the Execution plan, this was being executed as an index_merge, since all the columns had indexes on them, but not connected, but it had a very high cost;

Type Name Cost Rows
table data (index_merge) 92689.48 84079

However, by re-writing the query as a sub-query as follows;

select * from (
	select * from data where 
	(
   		L1 = 'no-match' OR L2 = 'X' 
	)
) data2
where 
  f1 = 'Y' OR p= 'Z' 	

The index_merge was drastically reduced;

Type Name Cost Rows
table data (index_merge) 1189.36 918

And most importantly, the time was reduced to a fraction of the overall cost. I’d also argue that the SQL was a bit easier to read also.

Categories: Uncategorized

Create your own Flash Briefing with #Alexa #Skills

So, this started because I wanted to listen to Italian news (RAI) on an English (UK) Amazon Alexa device, and the news source was not available. With a quick Google, I found someone who released a NodeJS based app that captured the feed from RAI, and reformatted the JSON into a format that is compatible with Alexa. I forked this repo here;

https://github.com/infiniteloopltd/alexa-flash-briefing-grr-radio-rai

Then, using Heroku, I deployed the Github repo onto a temporary domain, which you can see here;

https://flash-briefing.herokuapp.com/

Then, I headed over to Developer.Amazon.com, clicked on Alexa -> Create Alexa Skills -> Console

Then Create Skill -> Enter a Name (Italy News) – > Select a Language (English (UK)) ;

This should match your Alexa device exactly. English US and English UK are different !

Select Flash Briefing -> Create Skill

Add an error message , like “Sorry, failed”

Press “Add new Feed”

Fill in the fields, like preamble, name, Update frequency. The Content type should be audio, and the feed URL should be the Heroku Url above.

Then, from your alexa app in your phone, click More -> Settings -> Flash Briefing, and your new source should be in the list

Now, you’ll have a new news source when you say “Play News” to Alexa

Categories: Uncategorized

Storing temporary data in #Redis in C#

Redis is an in-memory database, designed for ultra-fast data retrieval. It’s great for short-lived data, that perhaps you only need to store for the duration of a user session, or transaction.

The AWS version, of Redis, under the name “ElasticCache” can only be accessed from within the AWS network, or specifically the Redis VPC. This is obviously designed to enforce recommended usage. You get no performance advantage if your Web server needs to traverse the Internet to reach your Redis server.

Here, I’ve used RedisCloud Hosted Redis database, rather than a local installation. But it has the advantage that it can be accessed from anywhere. Good for development, not designed for production. The key is in plain text, feel free to mess about with the server.

So, this was my use case: I wanted to store data temporarily, just for 2 seconds, and then delete it. It’s actually rather non-trivial with a standard MySQL database to do this in a scaleable way.

So, step 1 is to import a client library, here I picked StackExchange.Redis;

Install-Package StackExchange.Redis

Now, I connect to the Redis server, and write a value that will expire in 2 seconds;

const string endpoint = "redis-15557.c72.eu-west-1-2.ec2.cloud.redislabs.com:15557,password=JU455eaOlQZjVYExorUl1oFouO509Ptu";
var redis = ConnectionMultiplexer.Connect(endpoint);
var db = redis.GetDatabase();

const string setValue = "abcdefg";
db.StringSet("mykey", setValue, TimeSpan.FromSeconds(2));
    

If I read the value back instantly, I get the expected value of “abcdefg”. If I wait 3 seconds and try to read again, I get null;

string getValue = db.StringGet("mykey");
Console.WriteLine(getValue); // writes: "abcdefg"
Thread.Sleep(TimeSpan.FromSeconds(3));
string getValue2 = db.StringGet("mykey");
Console.WriteLine(getValue2); // writes nothing

The code is available to clone here; https://github.com/infiniteloopltd/RedisTest

Categories: Uncategorized

Run #postman collections in C# (.NET Core) hosted on AWS Lambda

Major Caveat, this is very much a work in progress, that I hope to complete one day, or that someone will complete, and be nice enough to share the code via a pull request.

But, here’s the repo on github: https://github.com/infiniteloopltd/PostmanSharp

The motivation behind this, was a way to define a Javascript library that could be used to execute Postman collections. Javascript can’t call most APIs, apart from those with CORS enabled, or hosted on the same server. However, Postman offers a nice way to define an API, and export that definition as a Postman collection.

So, what I did, was created a C# library that interprets a Postman collection, and carries out the calling of that API, using variables passed in. So far, It only does HTTP GET requests, but it could be expanded easily.

So, let’s start off with the library; which is defined as follows –

public class Postman
{
	private JObject postmanCollection;
	public Postman(string collection)
	{
	    postmanCollection = JObject.Parse(collection);
	}

	public string Execute(string function, string variables)
	{
	    var item = postmanCollection["item"].FirstOrDefault(
		j => j["name"] + "" == function);
	    if (item == null) throw new ArgumentException("function not recognized");
	    var request = item["request"];
	    var method = request["method"] + "";
	    if (method != "GET") 
		throw new NotImplementedException("Only HTTP GET is currently supported");
	    if (request["header"] is JArray headers && headers.Count > 0) 
		throw new NotImplementedException("HTTP Headers are not yet supported");
	    var url = request["url"]["raw"] + "";
	    var jVariables = JObject.Parse(variables);
	    foreach (var (key,value) in jVariables)
	    {
		url = url.Replace("{{" + key + "}}", value+"");
	    }
	    using var web = new WebClient {Encoding = Encoding.UTF8};
	    var result = web.DownloadString(url);
	    return result;
	}
}

You could use this from a console app, to call a postman-defined API, but to make it more interesting, I created an AWS Lambda function, and configured my API gateway to permit CORS with the following code:

public string FunctionHandler(LambdaRequest request, ILambdaContext context)
{
    string result;
    try
    {
	LambdaLogger.Log("FunctionHandler called");
	LambdaLogger.Log(request.body);
	if (!request.body.StartsWith("{"))
	{
	    request.body = Encoding.UTF8.GetString(Convert.FromBase64String(request.body));
	}
	var jsonBody = JObject.Parse(request.body);
	var collection = jsonBody["collection"] + "";
	var function = jsonBody["function"] + "";
	var variables = jsonBody["variables"] + "";
	var postman = new Postman(collection);
	result = postman.Execute(function, variables);
    }
    catch (Exception ex)
    {
	result = ex.ToString();
    }
    LambdaLogger.Log(result);
    return result; 
}

Where LambdaRequest is defined simply as:

public class LambdaRequest
{
    public string body { get; set; }
}

Now, once the Lambda is uploaded to AWS, and an API gateway, with CORS enabled is set up, then I defined my Javascript class as follows (actual url omitted)

class Postman
{
	constructor(collection)
	{
		this.collection = collection;
	}

	execute(postmanFunction, variables)
	{
		var url = "https://xxxxx.amazonaws.com/default/Postman";
		return this.postData(url, 
			{
			 "collection" : this.collection, 
			 "function" : postmanFunction, 
			 "variables" : JSON.stringify(variables)
			});
	}

	async postData(url = '', data = {}) {
	  const response = await fetch(url, {
		method: 'POST', 
		mode: 'cors', 
		body: JSON.stringify(data) 
	  });
	  return response.json(); 
	}

}

Then, it’s called something like this in the page;

var collection = ... 
var postman = new Postman(collection);
var variables = {
	address : "Dublin, Ireland"
};
postman.execute("Geolocation",variables).then( data => {
	console.log(data);
	var pos = data.Response.View[0].Result[0].Location.NavigationPosition[0];
	alert(pos.Latitude + "," + pos.Longitude);
});

Categories: Uncategorized

Record #Mp4 #H264 video from a webcam in C# (.NET Core)

This absolute masterpiece of a video was created with OpenCV and FFMediaToolkit in C#, to be honest, and you too can create a video like this using the Code posted on the Github repo here –

https://github.com/infiniteloopltd/WebcamDemo

(Fluffy Pink Flamingo not included)

This has thought me quite a bit about the underlying workings of the Bitmap file format, and I’m sure there is a better way to do this, I do welcome comments and suggestions below, but this may be helpful to someone.

Ok, first the basics –

My machine had two webcams, so I wanted to choose between them; therefore I used the DirectShowLib NuGet Package (Install-Package DirectShowLib) as follows –

private static int SelectCameraIndex()
{
	var cameras = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
	if (cameras.Length == 1) return 0;
	foreach (var (camera, index) in WithIndex(cameras))
	{
		Console.WriteLine($"{index}:{camera.Name}");
	}
	Console.WriteLine("Select a camera from the list above:");
	var camIndex = Convert.ToInt32(Console.ReadLine());
	return camIndex;
}

The “WithIndex” is a helper function that gives an indexer in a foreach loop, not essential, but elegant;

private static IEnumerable<(T item, int index)> WithIndex<T>(IEnumerable<T> source)
{
	return source.Select((item, index) => (item, index));
}

Now, what I wanted to do is initialize the capture device (the webcam) to capture images, and feed them into a Mp4 video for 5 seconds, then stop.

var camIndex = SelectCameraIndex();
_captureDevice = new VideoCapture(camIndex, VideoCapture.API.DShow)
	{FlipVertical = true};
_captureDevice.ImageGrabbed += CaptureDeviceImageGrabbed;
var settings = new VideoEncoderSettings(width: 
	_captureDevice.Width
	, height: _captureDevice.Height
	, framerate: 15
	, codec: VideoCodec.H264)
{
	EncoderPreset = EncoderPreset.Fast,
	CRF = 17 // Constant Rate Factor
};
// Download from https://github.com/BtbN/FFmpeg-Builds/releases
FFmpegLoader.FFmpegPath =
	@"C:\Users\fiach\source\repos\Webcam\FFmpeg\";
_videoOutput = MediaBuilder.CreateContainer(@"c:\temp\example.mp4").WithVideo(settings).Create();
_captureDevice.Start();
Thread.Sleep(TimeSpan.FromSeconds(5));
_captureDevice.Stop();
_captureDevice.Dispose();
_videoOutput.Dispose();

The FlipVertical setting, I will explain later, but effectively, I am telling the capture device (webcam) to trigger the CaptureImageGrabbed event every time a new image is available.

I am initialising a “Container” which will store it’s output at “C:\temp\example.mp4”. This container will be fed with images from the CaptureImageGrabbed event. The main thread sleeps for 5 seconds, as this capture-encode cycle happens, and once the thread wakes up, it stops the capture device, and cleans up the resources used.

So, lets look at the CaptureImageGrabbed event;

private static void CaptureDeviceImageGrabbed(object sender, System.EventArgs e)
{
	var frame = new Mat();
	_captureDevice.Retrieve(frame);
	var buffer = new VectorOfByte();
	var input = frame.ToImage<Bgr, byte>();
	CvInvoke.Imencode(".bmp", input, buffer);
	var bitmapData = buffer.ToArray();
	
	var headerLessData = RedBlueSwap(bitmapData.Skip(54).ToArray());
	var imageData = ImageData.FromArray(headerLessData, ImagePixelFormat.Rgb24, frame.Size);
	_videoOutput.Video.AddFrame(imageData);
}

This is where we deal with trying to mesh two incompatible image formats. The image captured from the camera, and the image required by the FFMPeg container. There are bound to be better ways to do this, but this is how I did this.

I retrieve the frame data from the camera, and then convert this into a Bitmap file format in memory, and store this in a buffer byte array. I then have to do some rather weird operations to convert the Bitmap file format into a image array used by FFMPeg.

The Bitmap image format has a 54 byte header, which can be removed by calling the Skip(54) method. If you don’t do this step, you get an error saying “‘Pixel buffer size doesn’t match size required by this image format.'”

The Bitmap image format also is written backwards, which means the image is upside down – hence the “FlipVertical” used in the capture device. Since it is backwards, it also means that the Red and Blue colour channels are reversed. This does create an interesting colour effect, and took me a while to work out what was wrong!

This is the code for the Red – Blue Swap;

private static byte[] RedBlueSwap(byte[] input)
{
	var output = new byte[input.Length];
	for (var i = 0; i < input.Length - 3; i += 3)
	{
		var r = input[i];
		var g = input[i + 1];
		var b = input[i + 2];
		output[i] = b;
		output[i + 1] = g;
		output[i + 2] = r;
	}
	return output;
}

And that’s all there was to it. If you run this code, it will take a 5 second video, and store it locally.

You also have access to the image data as the video is being made, so you can adapt this to do motion detection – image recognition, real-time video editing, whatever you need!

This version is for Windows, but the components used do have Linux versions also, so this will be a future project.

Categories: Uncategorized